Introduction
Dans le cadre de notre projet de statistiques, nous travaillerons sur
un jeu de données environnementales. Ce jeu de données est composé de
plusieurs fichiers qui contiennent des informations sur les oiseaux, les
stations de mesure, les caractéristiques des oiseaux, leurs régimes
alimentaires et la biodiversité.
Ce rapport a pour objectif de présenter les différentes analyses que
nous avons réalisées sur ces données. Il est composé de trois parties
principales dans lesquelles nous explorons les relations entre la
diversité des espèces d’oiseaux, l’artificialisation des sols et la
distance avec le centre-ville de Bordeaux. Nous avons également étudié
les régimes alimentaires des oiseaux et les modes de nidification en
fonction de certaines zones géographiques.
Vous trouverez des cartes, des graphiques, des tableaux, un sankie
plot ainsi qu’un sunburst plot qui nous permettront de découvrir la
mesure de la biodiversité.
L’ensemble de ces données sont tirées du travail des membres de
l’INRAE unité BioGeCo et du bureau de télédetection I-sea.
Vous trouverez de nombreux résultats comme plusieurs courbes de
diversité révélant la baisse significative de diversité dans les lieux
les plus artificialisés. Vous trouverez également l’entièreté de notre
cheminement pour arriver à nos résultats statistiques, notamment
concernant la distribution des espèces d’oiseaux observées en Gironde,
mais aussi des statistiques multivariées et descriptives.
Nous vous invitons à découvrir l’ensemble de nos analyses et à
explorer les différentes visualisations que nous avons réalisées pour
mieux comprendre les relations entre les différentes variables de notre
jeu de données. Toutes nos visualisations sont interactives et vous
permettent de zoomer, de déplacer et de cliquer sur les différents
éléments pour obtenir plus d’informations. Cela vous permettra d’avoir
une expérience plus immersive et vous permettra de créer vos propres
analyses, en parallèle à celles réalisées par nos soins.
Exploration des données
Pour commencer, nous chargeons les données et nous les explorons pour
mieux comprendre leur structure. Dans un premier temps, nous allons
ajouter une colonne à notre DataFrame qui contient les noms latins des
oiseaux afin de facilliter les analyses par la suite.
oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LE NOM LATIN DE L'OISEAU
my_split <- function(array, str = " \\| ") {
out <- rep(NA, length(array))
for (i in 1:length(array)) {
out[i] <- unlist(strsplit(array[i], str))[1]
}
return(out)
}
only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))
oiseaux$latin <- only_latin
oiseaux$annee <- as.numeric(substr(oiseaux$Date, 1, 4))
Par la suite, nous allons explorer les données pour mieux comprendre
la distribution des espèces d’oiseaux observées. Voici un tableau qui
montre les 10 espèces d’oiseaux les plus fréquemment observées dans
l’ensemble des données.
# LES ESPÈCES D'OISEAUX LES PLUS FRÉQUENTES OBSERVÉES DANS L'ENSEMBLE DES DONNÉES
as.data.frame(sort(table(oiseaux$latin), decreasing = TRUE)[1:10])
Nous allons maintenant explorer la fréquence des espèces d’oiseaux
observées dans l’ensemble des données par année. Voici, par ordre
alphabétique, le tableau mettant en évidence cette fréquence.
# FRÉQUENCE DES ESPÈCES D'OISEAUX OBSERVÉES DANS L'ENSEMBLE DES DONNÉES PAR ANNÉE
Annee <- my_split(as.vector(oiseaux$Date), str = "-")
oiseaux$Annee <- as.factor(Annee)
as.data.frame.matrix(table(oiseaux$latin, oiseaux$Annee))
Dans cette partie, nous allons explorer la mesure de la diversité à à
l’aide de plusieurs entropies. Nous nous intéresserons uniquement au
MOS11, c’est à dire les surfaces artificialisées. On prend comme buffer
size 500m.
Dans un premier temps, nous allons utiliser la proportion d’espèces
différentes observées dans une station pour mesurer la diversité. Dans
un deuxième temps, nous allons utiliser l’entropie de Shannon et enfin
l’indice de Simpson.
## Analyse de diversité par rapport à MOS11 et par année
denombrement <- oiseaux %>%
group_by(Code_Maille, annee, latin) %>%
summarise(sum = sum(Denombrement_min, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(Code_Maille))
denombrement$p <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
numerator <- denombrement$sum[i]
denominator <-
sum(denombrement$sum[which(denombrement$Code_Maille == denombrement$Code_Maille[i]
& denombrement$annee == denombrement$annee[i])])
denombrement$p[i] <- numerator / denominator
}
index <- denombrement %>%
group_by(Code_Maille, annee = factor(annee)) %>%
summarise(D1 = sum(p > 0, na.rm = TRUE),
D2 = exp(-sum(p * log(p))),
D3 = 1 / sum(p^2), .groups = "drop") %>%
arrange(desc(Code_Maille))
LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
index$MOS11 <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
index$MOS11[i] <- LUP$MOS11[which(index$Code_Maille[i] == LUP$ID & LUP$BufferSize == 500)]
}
Voici le graphique qui montre la relation entre la diversité et MOS11
pour chaque année expliquée par la proportion d’espèces.
ggplot(index, aes(x = MOS11, y = D1, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = " Proportion d’espèces en fonction de MOS11",
x = "MOS11",
y = "Nombre d\'espèces") +
theme_minimal() +
labs(colour = "Année") +
theme(legend.position = "bottom")

Ceci est le graphique qui montre la relation entre la diversité et
MOS11 pour chaque année expliquée par l’entropie de Shannon.
ggplot(index, aes(x = MOS11, y = D2, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = "Indice de Shanon en fonction de MOS11",
x = "MOS11",
y = "Indice de Shanon") +
theme_minimal() +
labs(colour = "Année") +
theme(legend.position = "bottom")

Ceci est le graphique qui montre la relation entre la diversité et
MOS11 pour chaque année expliquée par l’indice de Simpson.
ggplot(index, aes(x = MOS11, y = D3, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = "Indice de Simpson en fonction de MOS11",
x = "MOS11",
y = "Indice de Simpson") +
theme_minimal() +
labs(colour = "Année") +
theme(legend.position = "bottom")

La tendance globale est l’augmentation de la diversité au début de la
courbe jusqu’à atteindre un maximum puis une baisse quand le MOS11
augmente davantage. C’est-à-dire que, moins les sols sont
artificialisés, plus la diversité est grande avec une diversité maximale
atteinte quand le milieu est à la fois artificialisé mais présente
également des surfaces non artificialisées.
Notre deuxième partie se portera sur l’analyse de la diversité des
espèces d’oiseaux en fonction de la distance avec le centre-ville de
Bordeaux. On observera une tendance de diversité par rapport à la
distance de la maille avec le centre ville qui diffère légèrement par
rapport aux résultats ci-dessus. Pour ce faire, nous allons calculer
toutes les distances de chaque maille à PeyBerland, qui sera notre point
référent pour le centre.
Tendance de diversité par rapport à la distance avec le
centre-ville
PeyBerland <- data.frame("Latitude" = 44.838168, "Longitude" = -0.578803)
# On convertit les coordonnées de PeyBerland en sf
PeyBerland <- st_as_sf(PeyBerland, coords = c("Longitude", "Latitude"), crs = 4326)
# On va créer un dataframe qui contient les coordonnées de toutes les stations code_maille
coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)
# On va transformer les coordonnées de 2154 à 4326
coordinates <- st_transform(coordinates, crs = 4326)
# On va calculer les distances entre les stations et le centre ville PeyBerland
coordinates$Distance <- st_distance(coordinates, PeyBerland)
On ajoute les distances à nos données de diversité.
index$Distance <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
index$Distance[i] <- coordinates$Distance[which(index$Code_Maille[i] == coordinates$ID & coordinates$BufferSize == 500)]
}
par(mfrow = c(1, 3))
Pour faire l’analyse, on utilise les trois mesures de diversité que
nous avons utilisées précédemment.
Voici la courbe de diversité expliquée par la proportion
d’espèces.
ggplot(index, aes(x = Distance, y = D1, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = "D1 en fonction de la distance au centre-ville",
x = "Distance",
y = "D1") +
theme_minimal() +
theme(legend.position = "bottom")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Voici la courbe de diversité expliquée par l’entropie de Shannon.
ggplot(index, aes(x = Distance, y = D2, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = "D2 en fonction de la distance au centre-ville",
x = "Distance",
y = "D2") +
theme_minimal() +
theme(legend.position = "bottom")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Voici la courbe de diversité expliquée par l’indice de Simpson.
ggplot(index, aes(x = Distance, y = D3, color = as.factor(annee))) +
geom_point(size = 2) +
geom_smooth(method = "auto", se = TRUE, color = "black", alpha = 0.2) +
labs(title = "D3 en fonction de la distance au centre-ville",
x = "Distance",
y = "D3") +
theme_minimal() +
theme(legend.position = "bottom")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

La tendance globale est l’augmentation de la diversité au début de la
courbe jusqu’à atteindre un maximum puis une baisse quand la distance
avec le centre-ville augmente davantage. Nous pouvons voir que pour nos
trois mesures de diversité, le pic est atteint à environ 9km. La
diversité est donc plus grande lorsque la maille se trouver à environ
9km du centre-ville. Nous retrouvons donc la même observation qu’avec la
variable d’artificialisation des sols (MOSS11), car l’artificialisation
des sols et la distance avec le centre ville sont positivement corrélées
(peut-etre essayer de mesurer la correlation entre ces deux variables
sur nos données)
Par la suite, l’objectif va être de comprendre pourquoi ce pic de
diversité des espèces est observé à ce pourcentage d’artificialisation.
Pour ce faire, nous allons introduire un nouveau jeu de données sur les
caractéristiques des espèces d’oiseaux. Nous allons combiner ce jeu de
données avec les autres jeux de données afin d’en tirer des analyses,
principalement grâce à des cartes interactives.
oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LE NOM LATIN DE L'OISEAU
# LE NOM LATIN EST LE PREMIER NOM DE LA COLONNE "Nom_Taxon_Cite
# SI LE NOM CONTIENT UN "|", LE NOM LATIN EST LE PREMIER NOM AVANT LE "|"
# Diviser les noms
my_split <- function(array, str = " \\| ") {
out <- rep(NA, length(array))
for (i in 1:length(array)) {
out[i] <- unlist(strsplit(array[i], str))[1]
}
return(out)
}
# Tester la fonction
only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))
# On ajoute la nouvelle colonne au dataframe
oiseaux$latin <- only_latin
Voici le tableau qui représente le MOS11 pour chaque station de
mesure. Cette mesure nous indique à quel point le sol est
artificialisé.
# CRÉER UNE NOUVELLE COLONNE DANS LE DATAFRAME OISEAUX QUI CONTIENT LA VALEUR MOS11 DU POINT
filter <- LUP$BufferSize == 500
LUP_500_MOS11 <- LUP[filter, c("Geometry", "ID", "X", "Y", "BufferSize", "MOS11")]
rownames(LUP_500_MOS11) <- 1:nrow(LUP_500_MOS11)
LUP_500_MOS11[, c("ID", "MOS11")]
MOS11 <- rep(NA, nrow(oiseaux))
for (i in 1:nrow(oiseaux)) {
MOS11[i] <- which(oiseaux$Code_Maille[i] == LUP_500_MOS11$ID)
}
# Ajouter la colonne MOS11 au dataframe
oiseaux$MOS11 <- LUP_500_MOS11$MOS11[MOS11]
Analyses intéractives et géographiques
oiseaux <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
# CREATE A NEW COLUMN IN THE OISEAUX DATAFRAME THAT CONTAINS THE LATIN NAME OF THE BIRD
my_split <- function(array, str = " \\| ") {
out <- rep(NA, length(array))
for (i in 1:length(array)) {
out[i] <- unlist(strsplit(array[i], str))[1]
}
return (out)
}
only_latin <- my_split(as.vector(oiseaux$Nom_Taxon_Cite))
# length(unique(only_latin)) == length(unique(oiseaux$Code_Ref))
oiseaux$latin <- only_latin
oiseaux$annee <- as.numeric(substr(oiseaux$Date, 1, 4))
denombrement <- oiseaux %>%
group_by(Code_Maille, annee, latin) %>%
summarise(sum = sum(Denombrement_min, na.rm = TRUE), .groups = 'drop') %>%
arrange(desc(Code_Maille))
denombrement$p <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
numerator <- denombrement$sum[i]
denominator <-
sum(denombrement$sum[which(denombrement$Code_Maille == denombrement$Code_Maille[i]
& denombrement$annee == denombrement$annee[i])])
denombrement$p[i] <- numerator / denominator
}
index <- denombrement %>%
group_by(Code_Maille, annee = factor(annee)) %>%
summarise(D1 = sum(p > 0, na.rm = TRUE),
D2 = exp(-sum(p*log(p))),
D3 = 1 / sum(p^2), .groups = 'drop') %>%
arrange(desc(Code_Maille))
LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
index$MOS11 <- rep(NA, nrow(index))
for (i in 1:nrow(index)) {
index$MOS11[i] <- LUP$MOS11[which(index$Code_Maille[i] == LUP$ID & LUP$BufferSize == 1000)]
}
traits <- read.csv("data/birds/traits-statut-IUCN-biodivercite.csv", header = TRUE)
cite <- read.csv("data/birds/BiodiverCite_sites.csv", header = TRUE, sep=";")
#on veut traiter la table dénombrement qu'on appelera denombrementCarte où il restera pour chaque maille et pour chaque année le top 3 des oiseaux les plus observés sans la variable p
denombrementCarte <- denombrement %>%
group_by(Code_Maille, annee) %>%
top_n(3, sum) %>%
arrange(Code_Maille, annee, desc(sum)) %>%
ungroup() %>%
select(-p)
#on veut changer cette table pour faire apparaitre de nouvelles colonnes pour qu'il y ait : une ligne par maille et par année, et pour chaque oiseau, le nombre d'individus observés
denombrementCarte <- denombrementCarte %>%
pivot_wider(names_from = latin, values_from = sum, values_fill = 0)
#on veut ajouter les colonnes geometry, buffer size et MOS11 à la table denombrementCarte et pas les autres
denombrementCarte <- left_join(denombrementCarte, LUP, by = c("Code_Maille" = "ID"))
#on enlève les colonnes : MOS1, MOS2, MOS3, MOS4, MOS5, MOS6, MOS7, MOS8, MOS9, MOS10, MOS12, MOS13, MOS14
denombrementCarte <- denombrementCarte %>%
select(-c(MOS1, MOS2, MOS3, MOS4, MOS5, MOS6, MOS7, MOS8, MOS9, MOS10, MOS12, MOS13, MOS14))
# On garde que les lignes ou BufferSize == 500
denombrementCarte <- denombrementCarte %>%
filter(BufferSize == 500)
denombrementCarte <- st_as_sf(denombrementCarte, coords = c("X", "Y"), crs = 2154)
denombrementCarte <- st_transform(denombrementCarte, crs = 4326)
# On garde seuelement les valeurs ou annee = 2018
denombrementCarte <- denombrementCarte %>%
filter(annee == 2023)
denombrementCarte
Grâce à ce tableau, nous pouvons voir comment les données sont
structurées et remarquer notamment qu’il classe le nombre d’oiseaux par
maille et par année.
Dans la suite de ce rapport vous trouverez des analyses géographiques
et interactives qui vous permettront de visualiser comment les oiseaux
de la Gironde évoluent en fonction de l’artificialisation des sols. Vous
y trouverez des analyses sur les régimes alimentaires des oiseaux, les
niveaux de spécialisation des oiseaux en fonction de leur habitat
(Maille).
Voici la carte interactive qui montre les mailles de mesure et les
oiseaux les plus observés dans chaque maille. Nous vous invitons à
cliquer sur les cercles pour obtenir toutes les informations sur les
oiseaux.
# On garder que les colonnes qui nous intéressent, cad code_site et Nom_lieu
cite <- read.csv("data/birds/BiodiverCite_sites.csv", header = TRUE, sep=";")
cite <- cite %>%
select(code_site, Nom_lieu)
#On join les deux tables cite et denombrementCarte
denombrementCarte <- left_join(denombrementCarte, cite, by = c("Code_Maille" = "code_site"))
# Créer une chaîne de caractères pour les popups avec le top trois des oiseaux ayant la plus grande valeur
denombrementCarte$popup_text <- paste0("<strong>Maille:</strong> ", denombrementCarte$Nom_lieu, "<br>",
"<strong>Année:</strong> ", denombrementCarte$annee, "<br>",
"<strong>Top 3 des oiseaux:</strong>", "<br>")
dataframe <- as.data.frame(denombrementCarte)
# On enleve les colonnes Code_Maille, annee, BufferSize, MOS11, Geometry, geometry
dataframe <- dataframe %>%
select(-c(Code_Maille, annee, BufferSize, MOS11, Geometry, geometry, Nom_lieu))
# Ajouter les noms des oiseaux et leurs valeurs au popup_text pour chaque ligne
for (i in 1:nrow(dataframe)) {
top_birds <- sort(unlist(dataframe[i, -c(ncol(dataframe))]), decreasing = TRUE)[1:3]
top_bird_names <- names(top_birds)
denombrementCarte$popup_text[i] <- paste0(denombrementCarte$popup_text[i],
top_bird_names[1], ": ", top_birds[1], " - ", traits[which(traits$Nom.latin == top_bird_names[1]), "Niveau.de.spécialisation"], "<br>",
top_bird_names[2], ": ", top_birds[2], " - ", traits[which(traits$Nom.latin == top_bird_names[2]), "Niveau.de.spécialisation"], "<br>",
top_bird_names[3], ": ", top_birds[3], " - ", traits[which(traits$Nom.latin == top_bird_names[3]), "Niveau.de.spécialisation"])
}
pal <- colorNumeric("viridis", domain = denombrementCarte$MOS11)
leaflet(data = denombrementCarte) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircles(radius = 300, color = ~pal(MOS11), fillOpacity = 0.2, popup = ~popup_text) %>%
addLegend("bottomright", pal = pal, values = ~MOS11, title = "MOS11", position = "bottomright") %>%
addScaleBar(position = "bottomleft")
Grâce à cette carte, nous obtenons le classement (Top 3) des oiseaux
les plus observés dans chaque maille de mesure pour l’année 2023. Nous
avons également ajouté une information supplémentaire sur chaque oiseau
pour mettre en évidence son niveau de spécialisation afin de mieux
comprendre de quel type de milieu il a besoin pour vivre et la
géolocalisation sur la Gironde.
Nous pouvons voir que le niveau de spécialisation le plus répendu est
généraliste car on en retrouve au centre-ville et en périphérie.
Egalement, au centre ville, on retrouve des oiseaux de type Bâti et en
périphérie loins du centre-ville, on retrouve des oiseaux de type Fôret
et Agricole. Proche des points d’eau, on trouve des oiseaux de type Zone
humide.
Ainsi, les zones qui combinent à la fois végétation et bâtiments
seraient plus susceptibles d’accueillir des oiseaux avec des niveaux de
spécialisation variés, ce qui expliquerait l’augmentation du taux de
diversité observée dans les zones où se mélangent espaces verts et zones
urbanisées.
Il nous semblait intéressant de savoir quels étaient les régimes
alimentaires majoritaires principaux en fonction de chaque maille. Nous
avons donc créé un graphique qui montre la répartition des régimes
alimentaires pour chaque maille.
# changed the unmatchinng latin names to the correct ones to match alimentation
denombrement$latin[denombrement$latin == "Carduelis chloris"] <- "Chloris chloris"
denombrement$latin[denombrement$latin == "Carduelis spinus"] <- "Spinus spinus"
denombrement$latin[denombrement$latin == "Casmerodius albus"] <- "Ardea alba"
denombrement$latin[denombrement$latin == "Carduelis cannabina"] <- "Linaria cannabina"
no_info <- c("Himantopus himantopus", "Tringa ochropus",
"Caprimulgus europaeus", "Lanius senator",
"Dryocopus martius", "Emberiza calandra")
alimentation <- read.csv("data/birds/traits-statut-IUCN-biodivercite.csv", header = TRUE)
denombrement$regime_alimentaire <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
if (denombrement$latin[i] %in% no_info){
denombrement$regime_alimentaire[i] <- NA
}
else {
denombrement$regime_alimentaire[i] <-
alimentation$Régime.alimentaire[which(alimentation$Nom.latin == denombrement$latin[i])]
}
}
denombrement$regime_alimentaire <- as.factor(denombrement$regime_alimentaire)
plot_data = function (data, title) {
ggplot(data, aes(x="", y=sum, fill=regime_alimentaire)) +
geom_bar(stat="identity", width=0.1) +
coord_polar("y", start=0) +
ggtitle(paste("Station: ", as.character(title))) +
theme_void()
}
cite <- cite %>%
select(code_site, Nom_lieu)
#On join les deux tables cite et denombrementCarte
denombrement <- left_join(denombrement, cite, by = c("Code_Maille" = "code_site"))
N <- length(unique(denombrement$Code_Maille))
p <- vector("list", length = N)
for (i in 1:N) {
data <- denombrement[which(denombrement$Code_Maille == unique(denombrement$Code_Maille)[i]),]
data <- data %>% group_by(regime_alimentaire) %>% summarise(sum = sum(p, na.rm = TRUE))
p[[i]] <- plot_data(data, unique(denombrement$Nom_lieu)[i])
}
coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)
coordinates <- st_transform(coordinates, crs = 4326)
coordinates <- coordinates[coordinates$BufferSize == 500,]
# Remove the coordinates that are not in denombrement
for (i in seq_along(coordinates$ID)){
if (!(coordinates$ID[i] %in% unique(denombrement$Code_Maille))){
coordinates <- coordinates[-i,]
}
}
coordinates <- coordinates[order(coordinates$ID, decreasing = TRUE),]
pal <- colorNumeric("viridis", domain = coordinates$MOS11)
leaflet(data = coordinates) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircles(radius = 300, color = ~pal(MOS11),
fillOpacity = 0.5, group = "pnt") %>%
addLegend("bottomright", pal = pal, values = coordinates$MOS11, title = "MOS11") %>%
addScaleBar(position = "bottomleft") %>%
addPopupGraphs(p, width = 200, height = 200, group = "pnt")
Voici à quoi ressemble la carte interactive qui montre les régimes
alimentaires majoritaires principaux en fonction de chaque maille. Nous
pouvons voir qu’en général, le régime alimentaire dominant est le régime
alimentaire mixte, que cela soit au centre de Bordeaux ou en périphérie.
Il semble donc que le régime alimentaire de l’oiseau ne soit pas
véritablement impacté par l’artificialisation des sols. Essayons
maintenant d’étudier d’autre caratéristiques afin d’essayer de trouver
des raisons à ce pic de diversité.
denombrement$Nidification <- rep(NA, nrow(denombrement))
for (i in 1:nrow(denombrement)) {
if (denombrement$latin[i] %in% no_info){
denombrement$Nidification[i] <- NA
}
else {
denombrement$Nidification[i] <-
alimentation$Nidification[which(alimentation$Nom.latin == denombrement$latin[i])]
}
}
denombrement$Nidification <- as.factor(denombrement$Nidification)
plot_data = function (data, title) {
ggplot(data, aes(x="", y=sum, fill=Nidification)) +
geom_bar(stat="identity", width=0.1) +
coord_polar("y", start=0) +
ggtitle(paste("Station: ", as.character(title))) +
theme_void()
}
#On join les deux tables cite et denombrementCarte
N <- length(unique(denombrement$Code_Maille))
p <- vector("list", length = N)
for (i in 1:N) {
data <- denombrement[which(denombrement$Code_Maille == unique(denombrement$Code_Maille)[i]),]
data <- data %>% group_by(Nidification) %>% summarise(sum = sum(p, na.rm = TRUE))
p[[i]] <- plot_data(data, unique(denombrement$Nom_lieu)[i])
}
coordinates <- st_as_sf(LUP, coords = c("X", "Y"), crs = 2154)
coordinates <- st_transform(coordinates, crs = 4326)
coordinates <- coordinates[coordinates$BufferSize == 500,]
# Remove the coordinates that are not in denombrement
for (i in seq_along(coordinates$ID)){
if (!(coordinates$ID[i] %in% unique(denombrement$Code_Maille))){
coordinates <- coordinates[-i,]
}
}
coordinates <- coordinates[order(coordinates$ID, decreasing = TRUE),]
pal <- colorNumeric("viridis", domain = coordinates$MOS11)
leaflet(data = coordinates) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircles(radius = 300, color = ~pal(MOS11),
fillOpacity = 0.5, group = "pnt2") %>%
addLegend("bottomright", pal = pal, values = coordinates$MOS11, title = "MOS11") %>%
addScaleBar(position = "bottomleft") %>%
addPopupGraphs(p, width = 200, height = 200, group = "pnt2")
Cette carte illustre la répartition des types de nidification en
fonction des zones géographiques. Il est observé que dans les zones
centrales, la majorité des nids sont situés dans des cavités, ce qui
peut être attribué à la densité élevée de bâtiments et à la rareté de la
végétation en ville. Le mode de nidification au sol est le moins courant
dans ces zones, probablement en raison de la faible probabilité de
survie des oiseaux dans un environnement urbain avec un nid au sol.
En périphérie, les modes de nidification semblent plus diversifiés,
avec une prédominance de la nidification en buisson. La nidification
dans les arbres est également très répandue, et on retrouve aussi la
nidification en cavité. Le fait de ne pas être situé directement au
centre-ville semble offrir plus de possibilités de nidification, ce qui
pourrait expliquer une plus grande diversité d’espèces si on s’éloigne
légèrement du centre ville, grâce à une combinaison de bâtiments et de
végétation offrant plus de choix pour la nidification.
Pour aller plus loin
Cette section est dédiée à des analyses plus poussées qui pourraient
être réalisées pour mieux comprendre les données et les relations entre
les différentes variables. Vous trouverez un Parallel Coordinates Plot
ainsi qu’un sun burst plot qui illustrent les caractéristiques des
différentes espèces d’oiseaux.
Voici, ci-dessous le Parallel Coordinates Plot intéractif. Vous
pouvez cliquer sur les différentes espèces pour obtenir plus
d’informations sur chacune d’elles.
Exemple d’utilisation :
- Nous voulons savoir le régime alimentaire des oiseaux qui migrent.
Pour cela, il suffit de cliquer au niveau de “migrateur tardif” et de
cliquer sur “Végétarien”, “Mixte” ou “carnivore” pour obtenir les
espèces d’oiseaux qui correspondent à ces critères. Ceci est très utile
lorsqu’on veut comparer le nombre d’oiseau selon les caractéristiques
choisies ou même simplement rechercher l’espèce qui correspond à
certains critères que l’on veut étudier. Pour finir l’exemple, si on
clique au niveau de “Migrateur tardif”, on remarque qu’aucun oiseau
n’est végétarien. De plus, on peut affiner notre sélection pour voir
quelles espèces d’oiseaux sont des migrateurs tardifs et font leur nid
dans les buissons. On clique ainsi sur buisson et on voit que l’espèce
“Lanius collurio” correspond à ces critères. C’est une espèce carnivore
qui migre tardivement et fait son nid dans les buissons qui a un niveau
de spécialisation agricole et qui s’alimente en vol.
Voici une image de la pie-grièche écorcheur
(Lanius collurio), wikipedia
unique_level <- unique(birds_info[, "Niveau.de.spécialisation"])
unique_regime <- unique(birds_info[, "Régime.alimentaire"])
unique_technique <- unique(birds_info[, "Technique.d.alimentation"])
unique_nidi <- unique(birds_info[, "Nidification"])
unique_migration <- unique(birds_info[, "Période.de.migration"])
plot_ly(data.frame(), type = "parcoords", line = list(color = "blue"), height = 950,
dimensions = list(
list(
label = "Espèces",
range = c(0, length(birds_info[, "Nom.latin"]) + 1),
tickvals = 1:length(birds_info[, "Nom.latin"]),
ticktext = birds_info[, "Nom.latin"],
values = 1:length(birds_info[, "Nom.latin"])
),
list(
label = "Technique d'alimentation",
range = c(0, length(unique_technique) + 1),
tickvals = as.numeric(factor(unique_technique)),
ticktext = unique_technique,
values = as.numeric(factor(birds_info[, "Technique.d.alimentation"]))
),
list(
label = "Nidification",
range = c(0, length(unique_nidi) + 1),
tickvals = as.numeric(factor(unique_nidi)),
ticktext = unique_nidi,
values = as.numeric(factor(birds_info[, "Nidification"]))
),
list(
label = "Niveau de spécialisation",
range = c(0, length(unique_level) + 1),
tickvals = as.numeric(factor(unique_level)),
ticktext = unique_level,
values = as.numeric(factor(birds_info[, "Niveau.de.spécialisation"]))
),
list(
label = "Période de migration",
range = c(0, length(unique_migration) + 1),
tickvals = as.numeric(factor(unique_migration)),
ticktext = unique_migration,
values = as.numeric(factor(birds_info[, "Période.de.migration"]))
),
list(
label = "Régime alimentaire",
range = c(0, length(unique_regime) + 1),
tickvals = as.numeric(factor(unique_regime)),
ticktext = unique_regime,
values = as.numeric(factor(birds_info[, "Régime.alimentaire"]))
)
)
) %>% layout(
title = "Caractéristiques des différentes espèces d'oiseaux",
margin = list(l = 140, r = 55)
)
LUP <- read.csv("data/birds/LandUsePer_BM_2023_cartoISea.csv", header = TRUE)
LUP <- LUP[, c(c("ID", "BufferSize"), paste0("MOS", 1:14))]
birds_obs <- read.csv("data/birds/Oiseaux_up_to_2023.csv", header = TRUE, sep = "\t")
birds_obs <- birds_obs[, c(c("Code_Maille", "Date", "Nom_Taxon_Cite", "Denombrement_min"))]
birds_obs <- birds_obs %>%
rename(Year = Date, ID = Code_Maille, Latin = Nom_Taxon_Cite)
birds_obs[, "Year"] <- substr(birds_obs[, "Year"], start = 1, stop = 4)
birds_obs[, "Latin"] <- sapply(strsplit(birds_obs[, "Latin"], split = " | ", fixed = TRUE), function(x) x[1])
birds_obs <- birds_obs %>%
group_by(ID, Year, Latin) %>%
summarise(Sum = sum(Denombrement_min), .groups = "drop")
LUP_birds_obs <- merge(LUP, birds_obs, by = "ID")
unique_year <- unique(LUP_birds_obs[, "Year"])
unique_year <- unique_year[order(unique_year)]
ids <- c("Année", unique_year)
for (year in unique_year) {
ids <- c(ids, paste0(year, paste0(" - MOS", 1:14)))
}
for (year in unique_year) {
for (mos in paste0("MOS", 1:14)) {
for (specie in birds_info[, "Nom.latin"]) {
ids <- c(ids, paste0(year, paste0(paste0(" - ", mos), paste0(" - ", specie))))
}
}
}
labels <- c("Année", unique_year, rep(paste0("MOS", 1:14), times = length(unique_year)))
labels <- c(labels, rep(birds_info[, "Nom.latin"], times = 14 * length(unique_year)))
parents <- c("", rep("Année", times = length(unique_year)), rep(unique_year, each = 14))
for (year in unique_year) {
parents <- c(parents, paste0(year, rep(paste0(" - MOS", 1:14), each = length(birds_info[, "Nom.latin"]))))
}
values <- c(c(length(unique_year) * 14000, rep(14000, times = length(unique_year))), rep(1000, times = length(unique_year) * 14))
for (year in unique_year) {
for (mos in paste0("MOS", 1:14)) {
for (specie in birds_info[, "Nom.latin"]) {
tmp <- LUP_birds_obs[LUP_birds_obs["Year"] == year & LUP_birds_obs["Latin"] == specie & LUP_birds_obs["BufferSize"] == 500, ]
values <- c(values, sum(tmp[mos] * tmp["Sum"]))
}
tail_values <- values[(1 + length(values) - length(birds_info[, "Nom.latin"])):length(values)]
values[(1 + length(values) - length(birds_info[, "Nom.latin"])):length(values)] <- tail_values / sum(tail_values) * 1000
}
}
is_nan_values <- !is.na(values) & values != 0
ids <- ids[is_nan_values]
labels <- labels[is_nan_values]
parents <- parents[is_nan_values]
values <- values[is_nan_values]
Ci-dessous, vous trouverez un sunburst plot interactif qui illustre
la proportion des espèces d’oiseaux les plus couramment observées en
fonction de l’année et du MOS. Il est assez simple d’utilisation, il
suffit de cliquer sur les différentes parties du graphique pour obtenir
plus d’informations sur les espèces d’oiseaux les plus couramment
observées en fonction de l’année et du MOS.
plot_ly(
ids = ids,
labels = labels,
parents = parents,
values = values,
type = "sunburst",
branchvalues = "total",
maxdepth = 2,
insidetextorientation = "radial",
hoverinfo = "label+percent entry"
) %>% layout(
title = list(
text = "Proportion des espèces d'oiseaux les plus couramment observées<br>en fonction de l'année et du MOS",
y = 1.1
),
margin = list(t = 100)
)
LS0tCnRpdGxlOiAiUHJvamV0IHN0YXQgcG91ciBkb25uw6llcyBlbnZpcm9ubmVtZW50YWxlcyIKYXV0aG9yOiAiQWxleGFuZHJlIExleXMsIEJhcHRpc3RlIEdlcmJvdWluLCBIYW1hZCBUcmlhLCBMb3VpcyBEZWxpZ25hYywgVGjDqW8gTGF2YW5kaWVyIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiwgJVknKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAjIHBkZl9kb2N1bWVudDoKICAjICAgdG9jOiB0cnVlCiAgIyAgIHRvY19kZXB0aDogMgogICMgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAjICAgZGZfcHJpbnQ6IGthYmxlCiAgIyAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgo8c3R5bGU+CiAgLnRvY2lmeS1leHRlbmQtcGFnZSB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KPC9zdHlsZT4KCiMgSW50cm9kdWN0aW9uCgoKRGFucyBsZSBjYWRyZSBkZSBub3RyZSBwcm9qZXQgZGUgc3RhdGlzdGlxdWVzLCBub3VzIHRyYXZhaWxsZXJvbnMgc3VyIHVuIGpldSBkZSBkb25uw6llcyBlbnZpcm9ubmVtZW50YWxlcy4KQ2UgamV1IGRlIGRvbm7DqWVzIGVzdCBjb21wb3PDqSBkZSBwbHVzaWV1cnMgZmljaGllcnMgcXVpIGNvbnRpZW5uZW50IGRlcyBpbmZvcm1hdGlvbnMgc3VyIGxlcyBvaXNlYXV4LCBsZXMgc3RhdGlvbnMgZGUgbWVzdXJlLCBsZXMgY2FyYWN0w6lyaXN0aXF1ZXMgZGVzIG9pc2VhdXgsIGxldXJzIHLDqWdpbWVzIGFsaW1lbnRhaXJlcyBldCBsYSBiaW9kaXZlcnNpdMOpLgoKQ2UgcmFwcG9ydCBhIHBvdXIgb2JqZWN0aWYgZGUgcHLDqXNlbnRlciBsZXMgZGlmZsOpcmVudGVzIGFuYWx5c2VzIHF1ZSBub3VzIGF2b25zIHLDqWFsaXPDqWVzIHN1ciBjZXMgZG9ubsOpZXMuCklsIGVzdCBjb21wb3PDqSBkZSB0cm9pcyBwYXJ0aWVzIHByaW5jaXBhbGVzIGRhbnMgbGVzcXVlbGxlcyBub3VzIGV4cGxvcm9ucyBsZXMgcmVsYXRpb25zIGVudHJlIGxhIGRpdmVyc2l0w6kgZGVzIGVzcMOoY2VzIGQnb2lzZWF1eCwgbCdhcnRpZmljaWFsaXNhdGlvbiBkZXMgc29scyBldCBsYSBkaXN0YW5jZSBhdmVjIGxlIGNlbnRyZS12aWxsZSBkZSBCb3JkZWF1eC4KTm91cyBhdm9ucyDDqWdhbGVtZW50IMOpdHVkacOpIGxlcyByw6lnaW1lcyBhbGltZW50YWlyZXMgZGVzIG9pc2VhdXggZXQgbGVzIG1vZGVzIGRlIG5pZGlmaWNhdGlvbiBlbiBmb25jdGlvbiBkZSBjZXJ0YWluZXMgem9uZXMgZ8Opb2dyYXBoaXF1ZXMuCgpWb3VzIHRyb3V2ZXJleiBkZXMgY2FydGVzLCBkZXMgZ3JhcGhpcXVlcywgZGVzIHRhYmxlYXV4LCB1biBzYW5raWUgcGxvdCBhaW5zaSBxdSd1biBzdW5idXJzdCBwbG90IHF1aSBub3VzIHBlcm1ldHRyb250IGRlIGTDqWNvdXZyaXIgbGEgbWVzdXJlIGRlIGxhIGJpb2RpdmVyc2l0w6kuCgpMJ2Vuc2VtYmxlIGRlIGNlcyBkb25uw6llcyBzb250IHRpcsOpZXMgZHUgdHJhdmFpbCBkZXMgbWVtYnJlcyBkZSBsJ0lOUkFFIHVuaXTDqSBCaW9HZUNvIGV0IGR1IGJ1cmVhdSBkZSB0w6lsw6lkZXRlY3Rpb24gSS1zZWEuCgpWb3VzIHRyb3V2ZXJleiBkZSBub21icmV1eCByw6lzdWx0YXRzIGNvbW1lIHBsdXNpZXVycyBjb3VyYmVzIGRlIGRpdmVyc2l0w6kgcsOpdsOpbGFudCBsYSBiYWlzc2Ugc2lnbmlmaWNhdGl2ZSBkZSBkaXZlcnNpdMOpIGRhbnMgbGVzIGxpZXV4IGxlcyBwbHVzIGFydGlmaWNpYWxpc8Opcy4KVm91cyB0cm91dmVyZXogw6lnYWxlbWVudCBsJ2VudGnDqHJldMOpIGRlIG5vdHJlIGNoZW1pbmVtZW50IHBvdXIgYXJyaXZlciDDoCBub3MgcsOpc3VsdGF0cyBzdGF0aXN0aXF1ZXMsIG5vdGFtbWVudCBjb25jZXJuYW50IGxhIGRpc3RyaWJ1dGlvbiBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IG9ic2VydsOpZXMgZW4gR2lyb25kZSwgbWFpcyBhdXNzaSBkZXMgc3RhdGlzdGlxdWVzIG11bHRpdmFyacOpZXMgZXQgZGVzY3JpcHRpdmVzLgoKTm91cyB2b3VzIGludml0b25zIMOgIGTDqWNvdXZyaXIgbCdlbnNlbWJsZSBkZSBub3MgYW5hbHlzZXMgZXQgw6AgZXhwbG9yZXIgbGVzIGRpZmbDqXJlbnRlcyB2aXN1YWxpc2F0aW9ucyBxdWUgbm91cyBhdm9ucyByw6lhbGlzw6llcyBwb3VyIG1pZXV4IGNvbXByZW5kcmUgbGVzIHJlbGF0aW9ucyBlbnRyZSBsZXMgZGlmZsOpcmVudGVzIHZhcmlhYmxlcyBkZSBub3RyZSBqZXUgZGUgZG9ubsOpZXMuClRvdXRlcyBub3MgdmlzdWFsaXNhdGlvbnMgc29udCBpbnRlcmFjdGl2ZXMgZXQgdm91cyBwZXJtZXR0ZW50IGRlIHpvb21lciwgZGUgZMOpcGxhY2VyIGV0IGRlIGNsaXF1ZXIgc3VyIGxlcyBkaWZmw6lyZW50cyDDqWzDqW1lbnRzIHBvdXIgb2J0ZW5pciBwbHVzIGQnaW5mb3JtYXRpb25zLgpDZWxhIHZvdXMgcGVybWV0dHJhIGQnYXZvaXIgdW5lIGV4cMOpcmllbmNlIHBsdXMgaW1tZXJzaXZlIGV0IHZvdXMgcGVybWV0dHJhIGRlIGNyw6llciB2b3MgcHJvcHJlcyBhbmFseXNlcywgZW4gcGFyYWxsw6hsZSDDoCBjZWxsZXMgcsOpYWxpc8OpZXMgcGFyIG5vcyBzb2lucy4KCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFBhY2thZ2VzIGRlIGdlc3Rpb24gZGVzIGRvbm7DqWVzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQoKIyBQYWNrYWdlcyBwb3VyIHZpc3VhbGlzYXRpb24gZGVzIGRvbm7DqWVzCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3NwYXRpYWwpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShsYXR0aWNlKQpsaWJyYXJ5KHBsb3RseSkKCiMgUGFja2FnZXMgcG91ciB2aXN1YWxpc2F0aW9uIGRlIGNhcnRlcyBpbnTDqXJhY3RpdmVzCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShsZWFmcG9wKQpsaWJyYXJ5KGxlYWZsZXQuZXh0cmFzKQoKI0FDUApsaWJyYXJ5KEZhY3RvTWluZVIpCmxpYnJhcnkoZmFjdG9leHRyYSkKCmtuaXRyOjpvcHRzX2NodW5rJHNldChvdXQud2lkdGggPSAiMTAwJSIsIGVjaG8gPSBUUlVFKQpgYGAKCgoKCiMgRXhwbG9yYXRpb24gZGVzIGRvbm7DqWVzCgoKUG91ciBjb21tZW5jZXIsIG5vdXMgY2hhcmdlb25zIGxlcyBkb25uw6llcyBldCBub3VzIGxlcyBleHBsb3JvbnMgcG91ciBtaWV1eCBjb21wcmVuZHJlIGxldXIgc3RydWN0dXJlLgpEYW5zIHVuIHByZW1pZXIgdGVtcHMsIG5vdXMgYWxsb25zIGFqb3V0ZXIgdW5lIGNvbG9ubmUgw6Agbm90cmUgRGF0YUZyYW1lIHF1aSBjb250aWVudCBsZXMgbm9tcyBsYXRpbnMgZGVzIG9pc2VhdXggYWZpbiBkZSBmYWNpbGxpdGVyIGxlcyBhbmFseXNlcyBwYXIgbGEgc3VpdGUuCmBgYHtyfQpvaXNlYXV4IDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQojIENSw4lFUiBVTkUgTk9VVkVMTEUgQ09MT05ORSBEQU5TIExFIERBVEFGUkFNRSBPSVNFQVVYIFFVSSBDT05USUVOVCBMRSBOT00gTEFUSU4gREUgTCdPSVNFQVUKbXlfc3BsaXQgPC0gZnVuY3Rpb24oYXJyYXksIHN0ciA9ICIgXFx8ICIpIHsKICBvdXQgPC0gcmVwKE5BLCBsZW5ndGgoYXJyYXkpKQogIGZvciAoaSBpbiAxOmxlbmd0aChhcnJheSkpIHsKICAgIG91dFtpXSA8LSB1bmxpc3Qoc3Ryc3BsaXQoYXJyYXlbaV0sIHN0cikpWzFdCiAgfQogIHJldHVybihvdXQpCn0KCm9ubHlfbGF0aW4gPC0gbXlfc3BsaXQoYXMudmVjdG9yKG9pc2VhdXgkTm9tX1RheG9uX0NpdGUpKQoKb2lzZWF1eCRsYXRpbiA8LSBvbmx5X2xhdGluCm9pc2VhdXgkYW5uZWUgPC0gYXMubnVtZXJpYyhzdWJzdHIob2lzZWF1eCREYXRlLCAxLCA0KSkKYGBgCgoKUGFyIGxhIHN1aXRlLCBub3VzIGFsbG9ucyBleHBsb3JlciBsZXMgZG9ubsOpZXMgcG91ciBtaWV1eCBjb21wcmVuZHJlIGxhIGRpc3RyaWJ1dGlvbiBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IG9ic2VydsOpZXMuClZvaWNpIHVuIHRhYmxlYXUgcXVpIG1vbnRyZSBsZXMgMTAgZXNww6hjZXMgZCdvaXNlYXV4IGxlcyBwbHVzIGZyw6lxdWVtbWVudCBvYnNlcnbDqWVzIGRhbnMgbCdlbnNlbWJsZSBkZXMgZG9ubsOpZXMuCmBgYHtyfQojIExFUyBFU1DDiENFUyBEJ09JU0VBVVggTEVTIFBMVVMgRlLDiVFVRU5URVMgT0JTRVJWw4lFUyBEQU5TIEwnRU5TRU1CTEUgREVTIERPTk7DiUVTCmFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShvaXNlYXV4JGxhdGluKSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6MTBdKQpgYGAKCk5vdXMgYWxsb25zIG1haW50ZW5hbnQgZXhwbG9yZXIgbGEgZnLDqXF1ZW5jZSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IG9ic2VydsOpZXMgZGFucyBsJ2Vuc2VtYmxlIGRlcyBkb25uw6llcyBwYXIgYW5uw6llLgpWb2ljaSwgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUsIGxlIHRhYmxlYXUgbWV0dGFudCBlbiDDqXZpZGVuY2UgY2V0dGUgZnLDqXF1ZW5jZS4KCmBgYHtyfQojIEZSw4lRVUVOQ0UgREVTIEVTUMOIQ0VTIEQnT0lTRUFVWCBPQlNFUlbDiUVTIERBTlMgTCdFTlNFTUJMRSBERVMgRE9OTsOJRVMgUEFSIEFOTsOJRQpBbm5lZSA8LSBteV9zcGxpdChhcy52ZWN0b3Iob2lzZWF1eCREYXRlKSwgc3RyID0gIi0iKQpvaXNlYXV4JEFubmVlIDwtIGFzLmZhY3RvcihBbm5lZSkKYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUob2lzZWF1eCRsYXRpbiwgb2lzZWF1eCRBbm5lZSkpCmBgYAoKCkRhbnMgY2V0dGUgcGFydGllLCBub3VzIGFsbG9ucyBleHBsb3JlciBsYSBtZXN1cmUgZGUgbGEgZGl2ZXJzaXTDqSDDoCDDoCBsJ2FpZGUgZGUgcGx1c2lldXJzIGVudHJvcGllcy4KTm91cyBub3VzIGludMOpcmVzc2Vyb25zIHVuaXF1ZW1lbnQgYXUgTU9TMTEsIGMnZXN0IMOgIGRpcmUgbGVzIHN1cmZhY2VzIGFydGlmaWNpYWxpc8OpZXMuIE9uIHByZW5kIGNvbW1lIGJ1ZmZlciBzaXplIDUwMG0uCgpEYW5zIHVuIHByZW1pZXIgdGVtcHMsIG5vdXMgYWxsb25zIHV0aWxpc2VyIGxhIHByb3BvcnRpb24gZOKAmWVzcMOoY2VzIGRpZmbDqXJlbnRlcyBvYnNlcnbDqWVzIGRhbnMgdW5lIHN0YXRpb24gcG91ciBtZXN1cmVyIGxhIGRpdmVyc2l0w6kuIERhbnMgdW4gZGV1eGnDqG1lIHRlbXBzLCBub3VzIGFsbG9ucyB1dGlsaXNlciBs4oCZZW50cm9waWUgZGUgU2hhbm5vbiBldCBlbmZpbiBsJ2luZGljZSBkZSBTaW1wc29uLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIEFuYWx5c2UgZGUgZGl2ZXJzaXTDqSBwYXIgcmFwcG9ydCDDoCBNT1MxMSBldCBwYXIgYW5uw6llCgpkZW5vbWJyZW1lbnQgPC0gb2lzZWF1eCAlPiUKICBncm91cF9ieShDb2RlX01haWxsZSwgYW5uZWUsIGxhdGluKSAlPiUKICBzdW1tYXJpc2Uoc3VtID0gc3VtKERlbm9tYnJlbWVudF9taW4sIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGFycmFuZ2UoZGVzYyhDb2RlX01haWxsZSkpCgpkZW5vbWJyZW1lbnQkcCA8LSByZXAoTkEsIG5yb3coZGVub21icmVtZW50KSkKZm9yIChpIGluIDE6bnJvdyhkZW5vbWJyZW1lbnQpKSB7CiAgbnVtZXJhdG9yIDwtIGRlbm9tYnJlbWVudCRzdW1baV0KICBkZW5vbWluYXRvciA8LQogICAgc3VtKGRlbm9tYnJlbWVudCRzdW1bd2hpY2goZGVub21icmVtZW50JENvZGVfTWFpbGxlID09IGRlbm9tYnJlbWVudCRDb2RlX01haWxsZVtpXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBkZW5vbWJyZW1lbnQkYW5uZWUgPT0gZGVub21icmVtZW50JGFubmVlW2ldKV0pCiAgZGVub21icmVtZW50JHBbaV0gPC0gbnVtZXJhdG9yIC8gZGVub21pbmF0b3IKfQoKaW5kZXggPC0gZGVub21icmVtZW50ICU+JQogIGdyb3VwX2J5KENvZGVfTWFpbGxlLCBhbm5lZSA9IGZhY3Rvcihhbm5lZSkpICU+JQogIHN1bW1hcmlzZShEMSA9IHN1bShwID4gMCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgRDIgPSBleHAoLXN1bShwICogbG9nKHApKSksCiAgICAgICAgICAgIEQzID0gMSAvIHN1bShwXjIpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBhcnJhbmdlKGRlc2MoQ29kZV9NYWlsbGUpKQoKTFVQIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL0xhbmRVc2VQZXJfQk1fMjAyM19jYXJ0b0lTZWEuY3N2IiwgaGVhZGVyID0gVFJVRSkKaW5kZXgkTU9TMTEgPC0gcmVwKE5BLCBucm93KGluZGV4KSkKZm9yIChpIGluIDE6bnJvdyhpbmRleCkpIHsKICBpbmRleCRNT1MxMVtpXSA8LSBMVVAkTU9TMTFbd2hpY2goaW5kZXgkQ29kZV9NYWlsbGVbaV0gPT0gTFVQJElEICYgTFVQJEJ1ZmZlclNpemUgPT0gNTAwKV0KfQpgYGAKClZvaWNpIGxlIGdyYXBoaXF1ZSBxdWkgbW9udHJlIGxhIHJlbGF0aW9uIGVudHJlIGxhIGRpdmVyc2l0w6kgZXQgTU9TMTEgcG91ciBjaGFxdWUgYW5uw6llIGV4cGxpcXXDqWUgcGFyIGxhIHByb3BvcnRpb24gZCdlc3DDqGNlcy4KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFfQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gTU9TMTEsIHkgPSBEMSwgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKwogIGxhYnModGl0bGUgPSAiIFByb3BvcnRpb24gZOKAmWVzcMOoY2VzIGVuIGZvbmN0aW9uIGRlIE1PUzExIiwKICAgICAgIHggPSAiTU9TMTEiLAogICAgICAgeSA9ICJOb21icmUgZFwnZXNww6hjZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKGNvbG91ciA9ICJBbm7DqWUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKQ2VjaSBlc3QgbGUgZ3JhcGhpcXVlIHF1aSBtb250cmUgbGEgcmVsYXRpb24gZW50cmUgbGEgZGl2ZXJzaXTDqSBldCBNT1MxMSBwb3VyIGNoYXF1ZSBhbm7DqWUgZXhwbGlxdcOpZSBwYXIgbCdlbnRyb3BpZSBkZSBTaGFubm9uLgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0V9CmdncGxvdChpbmRleCwgYWVzKHggPSBNT1MxMSwgeSA9IEQyLCBjb2xvciA9IGFzLmZhY3Rvcihhbm5lZSkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJhdXRvIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC4yKSArCiAgbGFicyh0aXRsZSA9ICJJbmRpY2UgZGUgU2hhbm9uIGVuIGZvbmN0aW9uIGRlIE1PUzExIiwKICAgICAgIHggPSAiTU9TMTEiLAogICAgICAgeSA9ICJJbmRpY2UgZGUgU2hhbm9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyhjb2xvdXIgPSAiQW5uw6llIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCkNlY2kgZXN0IGxlIGdyYXBoaXF1ZSBxdWkgbW9udHJlIGxhIHJlbGF0aW9uIGVudHJlIGxhIGRpdmVyc2l0w6kgZXQgTU9TMTEgcG91ciBjaGFxdWUgYW5uw6llIGV4cGxpcXXDqWUgcGFyIGwnaW5kaWNlIGRlIFNpbXBzb24uCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlcnJvcj1GQUxTRX0KZ2dwbG90KGluZGV4LCBhZXMoeCA9IE1PUzExLCB5ID0gRDMsIGNvbG9yID0gYXMuZmFjdG9yKGFubmVlKSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImF1dG8iLCBzZSA9IFRSVUUsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHRpdGxlID0gIkluZGljZSBkZSBTaW1wc29uIGVuIGZvbmN0aW9uIGRlIE1PUzExIiwKICAgICAgIHggPSAiTU9TMTEiLAogICAgICAgeSA9ICJJbmRpY2UgZGUgU2ltcHNvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoY29sb3VyID0gIkFubsOpZSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpMYSB0ZW5kYW5jZSBnbG9iYWxlIGVzdCBsJ2F1Z21lbnRhdGlvbiBkZSBsYSBkaXZlcnNpdMOpIGF1IGTDqWJ1dCBkZSBsYSBjb3VyYmUganVzcXUnw6AgYXR0ZWluZHJlIHVuIG1heGltdW0gcHVpcyB1bmUgYmFpc3NlIHF1YW5kIGxlIE1PUzExIGF1Z21lbnRlIGRhdmFudGFnZS4gQydlc3Qtw6AtZGlyZSBxdWUsIG1vaW5zIGxlcyBzb2xzIHNvbnQgYXJ0aWZpY2lhbGlzw6lzLCBwbHVzIGxhIGRpdmVyc2l0w6kgZXN0IGdyYW5kZSBhdmVjIHVuZSBkaXZlcnNpdMOpIG1heGltYWxlIGF0dGVpbnRlIHF1YW5kIGxlIG1pbGlldSBlc3Qgw6AgbGEgZm9pcyBhcnRpZmljaWFsaXPDqSBtYWlzIHByw6lzZW50ZSDDqWdhbGVtZW50IGRlcyBzdXJmYWNlcyBub24gYXJ0aWZpY2lhbGlzw6llcy4gCgoKTm90cmUgZGV1eGnDqG1lIHBhcnRpZSBzZSBwb3J0ZXJhIHN1ciBsJ2FuYWx5c2UgZGUgbGEgZGl2ZXJzaXTDqSBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IGVuIGZvbmN0aW9uIGRlIGxhIGRpc3RhbmNlIGF2ZWMgbGUgY2VudHJlLXZpbGxlIGRlIEJvcmRlYXV4LgpPbiBvYnNlcnZlcmEgdW5lIHRlbmRhbmNlIGRlIGRpdmVyc2l0w6kgcGFyIHJhcHBvcnQgw6AgbGEgZGlzdGFuY2UgZGUgbGEgbWFpbGxlIGF2ZWMgbGUgY2VudHJlIHZpbGxlIHF1aSBkaWZmw6hyZSBsw6lnw6hyZW1lbnQgcGFyIHJhcHBvcnQgYXV4IHLDqXN1bHRhdHMgY2ktZGVzc3VzLgpQb3VyIGNlIGZhaXJlLCBub3VzIGFsbG9ucyBjYWxjdWxlciB0b3V0ZXMgbGVzIGRpc3RhbmNlcyBkZSBjaGFxdWUgbWFpbGxlIMOgIFBleUJlcmxhbmQsIHF1aSBzZXJhIG5vdHJlIHBvaW50IHLDqWbDqXJlbnQgcG91ciBsZSBjZW50cmUuIAoKIyBUZW5kYW5jZSBkZSBkaXZlcnNpdMOpIHBhciByYXBwb3J0IMOgIGxhIGRpc3RhbmNlIGF2ZWMgbGUgY2VudHJlLXZpbGxlCgpgYGB7cn0KUGV5QmVybGFuZCA8LSBkYXRhLmZyYW1lKCJMYXRpdHVkZSIgPSA0NC44MzgxNjgsICJMb25naXR1ZGUiID0gLTAuNTc4ODAzKQoKIyBPbiBjb252ZXJ0aXQgbGVzIGNvb3Jkb25uw6llcyBkZSBQZXlCZXJsYW5kIGVuIHNmCgpQZXlCZXJsYW5kIDwtIHN0X2FzX3NmKFBleUJlcmxhbmQsIGNvb3JkcyA9IGMoIkxvbmdpdHVkZSIsICJMYXRpdHVkZSIpLCBjcnMgPSA0MzI2KQoKIyBPbiB2YSBjcsOpZXIgdW4gZGF0YWZyYW1lIHF1aSBjb250aWVudCBsZXMgY29vcmRvbm7DqWVzIGRlIHRvdXRlcyBsZXMgc3RhdGlvbnMgY29kZV9tYWlsbGUKCmNvb3JkaW5hdGVzIDwtIHN0X2FzX3NmKExVUCwgY29vcmRzID0gYygiWCIsICJZIiksIGNycyA9IDIxNTQpCgojIE9uIHZhIHRyYW5zZm9ybWVyIGxlcyBjb29yZG9ubsOpZXMgZGUgMjE1NCDDoCA0MzI2Cgpjb29yZGluYXRlcyA8LSBzdF90cmFuc2Zvcm0oY29vcmRpbmF0ZXMsIGNycyA9IDQzMjYpCgojIE9uIHZhIGNhbGN1bGVyIGxlcyBkaXN0YW5jZXMgZW50cmUgbGVzIHN0YXRpb25zIGV0IGxlIGNlbnRyZSB2aWxsZSBQZXlCZXJsYW5kCgpjb29yZGluYXRlcyREaXN0YW5jZSA8LSBzdF9kaXN0YW5jZShjb29yZGluYXRlcywgUGV5QmVybGFuZCkKYGBgCgpPbiBham91dGUgbGVzIGRpc3RhbmNlcyDDoCBub3MgZG9ubsOpZXMgZGUgZGl2ZXJzaXTDqS4gCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KaW5kZXgkRGlzdGFuY2UgPC0gcmVwKE5BLCBucm93KGluZGV4KSkKZm9yIChpIGluIDE6bnJvdyhpbmRleCkpIHsKICBpbmRleCREaXN0YW5jZVtpXSA8LSBjb29yZGluYXRlcyREaXN0YW5jZVt3aGljaChpbmRleCRDb2RlX01haWxsZVtpXSA9PSBjb29yZGluYXRlcyRJRCAmIGNvb3JkaW5hdGVzJEJ1ZmZlclNpemUgPT0gNTAwKV0KfQoKcGFyKG1mcm93ID0gYygxLCAzKSkKYGBgCgpQb3VyIGZhaXJlIGwnYW5hbHlzZSwgb24gdXRpbGlzZSBsZXMgdHJvaXMgbWVzdXJlcyBkZSBkaXZlcnNpdMOpIHF1ZSBub3VzIGF2b25zIHV0aWxpc8OpZXMgcHLDqWPDqWRlbW1lbnQuCgpWb2ljaSBsYSBjb3VyYmUgZGUgZGl2ZXJzaXTDqSBleHBsaXF1w6llIHBhciBsYSBwcm9wb3J0aW9uIGQnZXNww6hjZXMuCmBgYHtyfQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gRGlzdGFuY2UsIHkgPSBEMSwgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKwogIGxhYnModGl0bGUgPSAiRDEgZW4gZm9uY3Rpb24gZGUgbGEgZGlzdGFuY2UgYXUgY2VudHJlLXZpbGxlIiwKICAgICAgIHggPSAiRGlzdGFuY2UiLAogICAgICAgeSA9ICJEMSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCgpWb2ljaSBsYSBjb3VyYmUgZGUgZGl2ZXJzaXTDqSBleHBsaXF1w6llIHBhciBsJ2VudHJvcGllIGRlIFNoYW5ub24uCmBgYHtyfQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gRGlzdGFuY2UsIHkgPSBEMiwgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKwogIGxhYnModGl0bGUgPSAiRDIgZW4gZm9uY3Rpb24gZGUgbGEgZGlzdGFuY2UgYXUgY2VudHJlLXZpbGxlIiwKICAgICAgIHggPSAiRGlzdGFuY2UiLAogICAgICAgeSA9ICJEMiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKClZvaWNpIGxhIGNvdXJiZSBkZSBkaXZlcnNpdMOpIGV4cGxpcXXDqWUgcGFyIGwnaW5kaWNlIGRlIFNpbXBzb24uCmBgYHtyfQpnZ3Bsb3QoaW5kZXgsIGFlcyh4ID0gRGlzdGFuY2UsIHkgPSBEMywgY29sb3IgPSBhcy5mYWN0b3IoYW5uZWUpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiYXV0byIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuMikgKwogIGxhYnModGl0bGUgPSAiRDMgZW4gZm9uY3Rpb24gZGUgbGEgZGlzdGFuY2UgYXUgY2VudHJlLXZpbGxlIiwKICAgICAgIHggPSAiRGlzdGFuY2UiLAogICAgICAgeSA9ICJEMyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCkxhIHRlbmRhbmNlIGdsb2JhbGUgZXN0IGwnYXVnbWVudGF0aW9uIGRlIGxhIGRpdmVyc2l0w6kgYXUgZMOpYnV0IGRlIGxhIGNvdXJiZSBqdXNxdSfDoCBhdHRlaW5kcmUgdW4gbWF4aW11bSBwdWlzIHVuZSBiYWlzc2UgcXVhbmQgbGEgZGlzdGFuY2UgYXZlYyBsZSBjZW50cmUtdmlsbGUgYXVnbWVudGUgZGF2YW50YWdlLiBOb3VzIHBvdXZvbnMgdm9pciBxdWUgcG91ciBub3MgdHJvaXMgbWVzdXJlcyBkZSBkaXZlcnNpdMOpLCBsZSBwaWMgZXN0IGF0dGVpbnQgw6AgZW52aXJvbiA5a20uIExhIGRpdmVyc2l0w6kgZXN0IGRvbmMgcGx1cyBncmFuZGUgbG9yc3F1ZSBsYSBtYWlsbGUgc2UgdHJvdXZlciDDoCBlbnZpcm9uIDlrbSBkdSBjZW50cmUtdmlsbGUuCk5vdXMgcmV0cm91dm9ucyBkb25jIGxhIG3Dqm1lIG9ic2VydmF0aW9uIHF1J2F2ZWMgbGEgdmFyaWFibGUgZCdhcnRpZmljaWFsaXNhdGlvbiBkZXMgc29scyAoTU9TUzExKSwgY2FyIGwnYXJ0aWZpY2lhbGlzYXRpb24gZGVzIHNvbHMgZXQgbGEgZGlzdGFuY2UgYXZlYyBsZSBjZW50cmUgdmlsbGUgc29udCBwb3NpdGl2ZW1lbnQgY29ycsOpbMOpZXMgKHBldXQtZXRyZSBlc3NheWVyIGRlIG1lc3VyZXIgbGEgY29ycmVsYXRpb24gZW50cmUgY2VzIGRldXggdmFyaWFibGVzIHN1ciBub3MgZG9ubsOpZXMpCgoKUGFyIGxhIHN1aXRlLCBsJ29iamVjdGlmIHZhIMOqdHJlIGRlIGNvbXByZW5kcmUgcG91cnF1b2kgY2UgcGljIGRlIGRpdmVyc2l0w6kgZGVzIGVzcMOoY2VzIGVzdCBvYnNlcnbDqSDDoCBjZSBwb3VyY2VudGFnZSBkJ2FydGlmaWNpYWxpc2F0aW9uLiBQb3VyIGNlIGZhaXJlLCBub3VzIGFsbG9ucyBpbnRyb2R1aXJlIHVuIG5vdXZlYXUgamV1IGRlIGRvbm7DqWVzIHN1ciBsZXMgY2FyYWN0w6lyaXN0aXF1ZXMgZGVzIGVzcMOoY2VzIGQnb2lzZWF1eC4KTm91cyBhbGxvbnMgY29tYmluZXIgY2UgamV1IGRlIGRvbm7DqWVzIGF2ZWMgbGVzIGF1dHJlcyBqZXV4IGRlIGRvbm7DqWVzIGFmaW4gZCdlbiB0aXJlciBkZXMgYW5hbHlzZXMsIHByaW5jaXBhbGVtZW50IGdyw6JjZSDDoCBkZXMgY2FydGVzIGludGVyYWN0aXZlcy4gCgoKYGBge3J9Cm9pc2VhdXggPC0gcmVhZC5jc3YoImRhdGEvYmlyZHMvT2lzZWF1eF91cF90b18yMDIzLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIpCkxVUCA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9MYW5kVXNlUGVyX0JNXzIwMjNfY2FydG9JU2VhLmNzdiIsIGhlYWRlciA9IFRSVUUpCmBgYAoKYGBge3J9CiMgQ1LDiUVSIFVORSBOT1VWRUxMRSBDT0xPTk5FIERBTlMgTEUgREFUQUZSQU1FIE9JU0VBVVggUVVJIENPTlRJRU5UIExFIE5PTSBMQVRJTiBERSBMJ09JU0VBVQojIExFIE5PTSBMQVRJTiBFU1QgTEUgUFJFTUlFUiBOT00gREUgTEEgQ09MT05ORSAiTm9tX1RheG9uX0NpdGUKIyBTSSBMRSBOT00gQ09OVElFTlQgVU4gInwiLCBMRSBOT00gTEFUSU4gRVNUIExFIFBSRU1JRVIgTk9NIEFWQU5UIExFICJ8IgoKIyBEaXZpc2VyIGxlcyBub21zCm15X3NwbGl0IDwtIGZ1bmN0aW9uKGFycmF5LCBzdHIgPSAiIFxcfCAiKSB7CiAgb3V0IDwtIHJlcChOQSwgbGVuZ3RoKGFycmF5KSkKICBmb3IgKGkgaW4gMTpsZW5ndGgoYXJyYXkpKSB7CiAgICBvdXRbaV0gPC0gdW5saXN0KHN0cnNwbGl0KGFycmF5W2ldLCBzdHIpKVsxXQogIH0KICByZXR1cm4ob3V0KQp9CgojIFRlc3RlciBsYSBmb25jdGlvbgpvbmx5X2xhdGluIDwtIG15X3NwbGl0KGFzLnZlY3RvcihvaXNlYXV4JE5vbV9UYXhvbl9DaXRlKSkKCiMgT24gYWpvdXRlIGxhIG5vdXZlbGxlIGNvbG9ubmUgYXUgZGF0YWZyYW1lCm9pc2VhdXgkbGF0aW4gPC0gb25seV9sYXRpbgpgYGAKClZvaWNpIGxlIHRhYmxlYXUgcXVpIHJlcHLDqXNlbnRlIGxlIE1PUzExIHBvdXIgY2hhcXVlIHN0YXRpb24gZGUgbWVzdXJlLgpDZXR0ZSBtZXN1cmUgbm91cyBpbmRpcXVlIMOgIHF1ZWwgcG9pbnQgbGUgc29sIGVzdCBhcnRpZmljaWFsaXPDqS4KYGBge3J9CiMgQ1LDiUVSIFVORSBOT1VWRUxMRSBDT0xPTk5FIERBTlMgTEUgREFUQUZSQU1FIE9JU0VBVVggUVVJIENPTlRJRU5UIExBIFZBTEVVUiBNT1MxMSBEVSBQT0lOVApmaWx0ZXIgPC0gTFVQJEJ1ZmZlclNpemUgPT0gNTAwCkxVUF81MDBfTU9TMTEgPC0gTFVQW2ZpbHRlciwgYygiR2VvbWV0cnkiLCAiSUQiLCAiWCIsICJZIiwgIkJ1ZmZlclNpemUiLCAiTU9TMTEiKV0Kcm93bmFtZXMoTFVQXzUwMF9NT1MxMSkgPC0gMTpucm93KExVUF81MDBfTU9TMTEpCkxVUF81MDBfTU9TMTFbLCBjKCJJRCIsICJNT1MxMSIpXQoKTU9TMTEgPC0gcmVwKE5BLCBucm93KG9pc2VhdXgpKQpmb3IgKGkgaW4gMTpucm93KG9pc2VhdXgpKSB7CiAgTU9TMTFbaV0gPC0gd2hpY2gob2lzZWF1eCRDb2RlX01haWxsZVtpXSA9PSBMVVBfNTAwX01PUzExJElEKQp9CgojIEFqb3V0ZXIgbGEgY29sb25uZSBNT1MxMSBhdSBkYXRhZnJhbWUKb2lzZWF1eCRNT1MxMSA8LSBMVVBfNTAwX01PUzExJE1PUzExW01PUzExXQpgYGAKCgojIEFuYWx5c2VzIGludMOpcmFjdGl2ZXMgZXQgZ8Opb2dyYXBoaXF1ZXMKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpvaXNlYXV4IDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQojIENSRUFURSBBIE5FVyBDT0xVTU4gSU4gVEhFIE9JU0VBVVggREFUQUZSQU1FIFRIQVQgQ09OVEFJTlMgVEhFIExBVElOIE5BTUUgT0YgVEhFIEJJUkQKbXlfc3BsaXQgPC0gZnVuY3Rpb24oYXJyYXksIHN0ciA9ICIgXFx8ICIpIHsKICBvdXQgPC0gcmVwKE5BLCBsZW5ndGgoYXJyYXkpKQogIGZvciAoaSBpbiAxOmxlbmd0aChhcnJheSkpIHsKICAgIG91dFtpXSA8LSB1bmxpc3Qoc3Ryc3BsaXQoYXJyYXlbaV0sIHN0cikpWzFdCiAgfQogIHJldHVybiAob3V0KQp9Cgpvbmx5X2xhdGluIDwtIG15X3NwbGl0KGFzLnZlY3RvcihvaXNlYXV4JE5vbV9UYXhvbl9DaXRlKSkKIyBsZW5ndGgodW5pcXVlKG9ubHlfbGF0aW4pKSA9PSBsZW5ndGgodW5pcXVlKG9pc2VhdXgkQ29kZV9SZWYpKQoKb2lzZWF1eCRsYXRpbiA8LSBvbmx5X2xhdGluCm9pc2VhdXgkYW5uZWUgPC0gYXMubnVtZXJpYyhzdWJzdHIob2lzZWF1eCREYXRlLCAxLCA0KSkKCmRlbm9tYnJlbWVudCA8LSBvaXNlYXV4ICU+JQogIGdyb3VwX2J5KENvZGVfTWFpbGxlLCBhbm5lZSwgbGF0aW4pICU+JQogIHN1bW1hcmlzZShzdW0gPSBzdW0oRGVub21icmVtZW50X21pbiwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lCiAgYXJyYW5nZShkZXNjKENvZGVfTWFpbGxlKSkKCmRlbm9tYnJlbWVudCRwIDwtIHJlcChOQSwgbnJvdyhkZW5vbWJyZW1lbnQpKQpmb3IgKGkgaW4gMTpucm93KGRlbm9tYnJlbWVudCkpIHsKICBudW1lcmF0b3IgPC0gZGVub21icmVtZW50JHN1bVtpXQogIGRlbm9taW5hdG9yIDwtIAogICAgc3VtKGRlbm9tYnJlbWVudCRzdW1bd2hpY2goZGVub21icmVtZW50JENvZGVfTWFpbGxlID09IGRlbm9tYnJlbWVudCRDb2RlX01haWxsZVtpXSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgZGVub21icmVtZW50JGFubmVlID09IGRlbm9tYnJlbWVudCRhbm5lZVtpXSldKQogIGRlbm9tYnJlbWVudCRwW2ldIDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yCn0KCmluZGV4IDwtIGRlbm9tYnJlbWVudCAlPiUKICBncm91cF9ieShDb2RlX01haWxsZSwgYW5uZWUgPSBmYWN0b3IoYW5uZWUpKSAlPiUKICBzdW1tYXJpc2UoRDEgPSBzdW0ocCA+IDAsIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgICBEMiA9IGV4cCgtc3VtKHAqbG9nKHApKSksIAogICAgICAgICAgICBEMyA9IDEgLyBzdW0ocF4yKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lCiAgYXJyYW5nZShkZXNjKENvZGVfTWFpbGxlKSkKCkxVUCA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9MYW5kVXNlUGVyX0JNXzIwMjNfY2FydG9JU2VhLmNzdiIsIGhlYWRlciA9IFRSVUUpCmluZGV4JE1PUzExIDwtIHJlcChOQSwgbnJvdyhpbmRleCkpCmZvciAoaSBpbiAxOm5yb3coaW5kZXgpKSB7CiAgaW5kZXgkTU9TMTFbaV0gPC0gTFVQJE1PUzExW3doaWNoKGluZGV4JENvZGVfTWFpbGxlW2ldID09IExVUCRJRCAmIExVUCRCdWZmZXJTaXplID09IDEwMDApXQp9CgoKdHJhaXRzIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL3RyYWl0cy1zdGF0dXQtSVVDTi1iaW9kaXZlcmNpdGUuY3N2IiwgaGVhZGVyID0gVFJVRSkKY2l0ZSA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy9CaW9kaXZlckNpdGVfc2l0ZXMuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwPSI7IikKCiNvbiB2ZXV0IHRyYWl0ZXIgbGEgdGFibGUgZMOpbm9tYnJlbWVudCBxdSdvbiBhcHBlbGVyYSBkZW5vbWJyZW1lbnRDYXJ0ZSBvw7kgaWwgcmVzdGVyYSBwb3VyIGNoYXF1ZSBtYWlsbGUgZXQgcG91ciBjaGFxdWUgYW5uw6llIGxlIHRvcCAzIGRlcyBvaXNlYXV4IGxlcyBwbHVzIG9ic2VydsOpcyBzYW5zIGxhIHZhcmlhYmxlIHAKCmRlbm9tYnJlbWVudENhcnRlIDwtIGRlbm9tYnJlbWVudCAlPiUKICBncm91cF9ieShDb2RlX01haWxsZSwgYW5uZWUpICU+JQogIHRvcF9uKDMsIHN1bSkgJT4lCiAgYXJyYW5nZShDb2RlX01haWxsZSwgYW5uZWUsIGRlc2Moc3VtKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtcCkKCgojb24gdmV1dCBjaGFuZ2VyIGNldHRlIHRhYmxlIHBvdXIgZmFpcmUgYXBwYXJhaXRyZSBkZSBub3V2ZWxsZXMgY29sb25uZXMgcG91ciBxdSdpbCB5IGFpdCA6IHVuZSBsaWduZSBwYXIgbWFpbGxlIGV0IHBhciBhbm7DqWUsIGV0IHBvdXIgY2hhcXVlIG9pc2VhdSwgbGUgbm9tYnJlIGQnaW5kaXZpZHVzIG9ic2VydsOpcwoKZGVub21icmVtZW50Q2FydGUgPC0gZGVub21icmVtZW50Q2FydGUgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGxhdGluLCB2YWx1ZXNfZnJvbSA9IHN1bSwgdmFsdWVzX2ZpbGwgPSAwKQoKCiNvbiB2ZXV0IGFqb3V0ZXIgbGVzIGNvbG9ubmVzIGdlb21ldHJ5LCBidWZmZXIgc2l6ZSBldCBNT1MxMSDDoCBsYSB0YWJsZSBkZW5vbWJyZW1lbnRDYXJ0ZSBldCBwYXMgbGVzIGF1dHJlcwoKZGVub21icmVtZW50Q2FydGUgPC0gbGVmdF9qb2luKGRlbm9tYnJlbWVudENhcnRlLCBMVVAsIGJ5ID0gYygiQ29kZV9NYWlsbGUiID0gIklEIikpCgojb24gZW5sw6h2ZSBsZXMgY29sb25uZXMgOiBNT1MxLCBNT1MyLCBNT1MzLCBNT1M0LCBNT1M1LCBNT1M2LCBNT1M3LCBNT1M4LCBNT1M5LCBNT1MxMCwgTU9TMTIsIE1PUzEzLCBNT1MxNAoKZGVub21icmVtZW50Q2FydGUgPC0gZGVub21icmVtZW50Q2FydGUgJT4lCiAgc2VsZWN0KC1jKE1PUzEsIE1PUzIsIE1PUzMsIE1PUzQsIE1PUzUsIE1PUzYsIE1PUzcsIE1PUzgsIE1PUzksIE1PUzEwLCBNT1MxMiwgTU9TMTMsIE1PUzE0KSkKCiMgT24gZ2FyZGUgcXVlIGxlcyBsaWduZXMgb3UgQnVmZmVyU2l6ZSA9PSA1MDAKZGVub21icmVtZW50Q2FydGUgPC0gZGVub21icmVtZW50Q2FydGUgJT4lCiAgZmlsdGVyKEJ1ZmZlclNpemUgPT0gNTAwKQoKZGVub21icmVtZW50Q2FydGUgPC0gc3RfYXNfc2YoZGVub21icmVtZW50Q2FydGUsIGNvb3JkcyA9IGMoIlgiLCAiWSIpLCBjcnMgPSAyMTU0KQpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBzdF90cmFuc2Zvcm0oZGVub21icmVtZW50Q2FydGUsIGNycyA9IDQzMjYpCgojIE9uIGdhcmRlIHNldWVsZW1lbnQgbGVzIHZhbGV1cnMgb3UgYW5uZWUgPSAyMDE4CgpkZW5vbWJyZW1lbnRDYXJ0ZSA8LSBkZW5vbWJyZW1lbnRDYXJ0ZSAlPiUKICBmaWx0ZXIoYW5uZWUgPT0gMjAyMykKCmRlbm9tYnJlbWVudENhcnRlCmBgYApHcsOiY2Ugw6AgY2UgdGFibGVhdSwgbm91cyBwb3V2b25zIHZvaXIgY29tbWVudCBsZXMgZG9ubsOpZXMgc29udCBzdHJ1Y3R1csOpZXMgZXQgcmVtYXJxdWVyIG5vdGFtbWVudCBxdSdpbCBjbGFzc2UgbGUgbm9tYnJlIGQnb2lzZWF1eCBwYXIgbWFpbGxlIGV0IHBhciBhbm7DqWUuCgoKRGFucyBsYSBzdWl0ZSBkZSBjZSByYXBwb3J0IHZvdXMgdHJvdXZlcmV6IGRlcyBhbmFseXNlcyBnw6lvZ3JhcGhpcXVlcyBldCBpbnRlcmFjdGl2ZXMgcXVpIHZvdXMgcGVybWV0dHJvbnQgZGUgdmlzdWFsaXNlciBjb21tZW50IGxlcyBvaXNlYXV4IGRlIGxhIEdpcm9uZGUgw6l2b2x1ZW50IGVuIGZvbmN0aW9uIGRlIGwnYXJ0aWZpY2lhbGlzYXRpb24gZGVzIHNvbHMuClZvdXMgeSB0cm91dmVyZXogZGVzIGFuYWx5c2VzIHN1ciBsZXMgcsOpZ2ltZXMgYWxpbWVudGFpcmVzIGRlcyBvaXNlYXV4LCBsZXMgbml2ZWF1eCBkZSBzcMOpY2lhbGlzYXRpb24gZGVzIG9pc2VhdXggZW4gZm9uY3Rpb24gZGUgbGV1ciBoYWJpdGF0IChNYWlsbGUpLgoKVm9pY2kgbGEgY2FydGUgaW50ZXJhY3RpdmUgcXVpIG1vbnRyZSBsZXMgbWFpbGxlcyBkZSBtZXN1cmUgZXQgbGVzIG9pc2VhdXggbGVzIHBsdXMgb2JzZXJ2w6lzIGRhbnMgY2hhcXVlIG1haWxsZS4KTm91cyB2b3VzIGludml0b25zIMOgIGNsaXF1ZXIgc3VyIGxlcyBjZXJjbGVzIHBvdXIgb2J0ZW5pciB0b3V0ZXMgbGVzIGluZm9ybWF0aW9ucyBzdXIgbGVzIG9pc2VhdXguCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgT24gZ2FyZGVyIHF1ZSBsZXMgY29sb25uZXMgcXVpIG5vdXMgaW50w6lyZXNzZW50LCBjYWQgY29kZV9zaXRlIGV0IE5vbV9saWV1CgpjaXRlIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL0Jpb2RpdmVyQ2l0ZV9zaXRlcy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXA9IjsiKQpjaXRlIDwtIGNpdGUgJT4lCiAgc2VsZWN0KGNvZGVfc2l0ZSwgTm9tX2xpZXUpCgojT24gam9pbiBsZXMgZGV1eCB0YWJsZXMgY2l0ZSBldCBkZW5vbWJyZW1lbnRDYXJ0ZQoKZGVub21icmVtZW50Q2FydGUgPC0gbGVmdF9qb2luKGRlbm9tYnJlbWVudENhcnRlLCBjaXRlLCBieSA9IGMoIkNvZGVfTWFpbGxlIiA9ICJjb2RlX3NpdGUiKSkKCiMgQ3LDqWVyIHVuZSBjaGHDrm5lIGRlIGNhcmFjdMOocmVzIHBvdXIgbGVzIHBvcHVwcyBhdmVjIGxlIHRvcCB0cm9pcyBkZXMgb2lzZWF1eCBheWFudCBsYSBwbHVzIGdyYW5kZSB2YWxldXIKZGVub21icmVtZW50Q2FydGUkcG9wdXBfdGV4dCA8LSBwYXN0ZTAoIjxzdHJvbmc+TWFpbGxlOjwvc3Ryb25nPiAiLCBkZW5vbWJyZW1lbnRDYXJ0ZSROb21fbGlldSwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8c3Ryb25nPkFubsOpZTo8L3N0cm9uZz4gIiwgZGVub21icmVtZW50Q2FydGUkYW5uZWUsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPHN0cm9uZz5Ub3AgMyBkZXMgb2lzZWF1eDo8L3N0cm9uZz4iLCAiPGJyPiIpCgpkYXRhZnJhbWUgPC0gYXMuZGF0YS5mcmFtZShkZW5vbWJyZW1lbnRDYXJ0ZSkKCiMgT24gZW5sZXZlIGxlcyBjb2xvbm5lcyBDb2RlX01haWxsZSwgYW5uZWUsIEJ1ZmZlclNpemUsIE1PUzExLCBHZW9tZXRyeSwgZ2VvbWV0cnkKZGF0YWZyYW1lIDwtIGRhdGFmcmFtZSAlPiUKICBzZWxlY3QoLWMoQ29kZV9NYWlsbGUsIGFubmVlLCBCdWZmZXJTaXplLCBNT1MxMSwgR2VvbWV0cnksIGdlb21ldHJ5LCBOb21fbGlldSkpCgojIEFqb3V0ZXIgbGVzIG5vbXMgZGVzIG9pc2VhdXggZXQgbGV1cnMgdmFsZXVycyBhdSBwb3B1cF90ZXh0IHBvdXIgY2hhcXVlIGxpZ25lCmZvciAoaSBpbiAxOm5yb3coZGF0YWZyYW1lKSkgewogIHRvcF9iaXJkcyA8LSBzb3J0KHVubGlzdChkYXRhZnJhbWVbaSwgLWMobmNvbChkYXRhZnJhbWUpKV0pLCBkZWNyZWFzaW5nID0gVFJVRSlbMTozXQogIHRvcF9iaXJkX25hbWVzIDwtIG5hbWVzKHRvcF9iaXJkcykKICBkZW5vbWJyZW1lbnRDYXJ0ZSRwb3B1cF90ZXh0W2ldIDwtIHBhc3RlMChkZW5vbWJyZW1lbnRDYXJ0ZSRwb3B1cF90ZXh0W2ldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvcF9iaXJkX25hbWVzWzFdLCAiOiAiLCB0b3BfYmlyZHNbMV0sICIgLSAiLCB0cmFpdHNbd2hpY2godHJhaXRzJE5vbS5sYXRpbiA9PSB0b3BfYmlyZF9uYW1lc1sxXSksICJOaXZlYXUuZGUuc3DDqWNpYWxpc2F0aW9uIl0sICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYmlyZF9uYW1lc1syXSwgIjogIiwgdG9wX2JpcmRzWzJdLCAiIC0gIiwgdHJhaXRzW3doaWNoKHRyYWl0cyROb20ubGF0aW4gPT0gdG9wX2JpcmRfbmFtZXNbMl0pLCAiTml2ZWF1LmRlLnNww6ljaWFsaXNhdGlvbiJdLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wX2JpcmRfbmFtZXNbM10sICI6ICIsIHRvcF9iaXJkc1szXSwgIiAtICIsIHRyYWl0c1t3aGljaCh0cmFpdHMkTm9tLmxhdGluID09IHRvcF9iaXJkX25hbWVzWzNdKSwgIk5pdmVhdS5kZS5zcMOpY2lhbGlzYXRpb24iXSkKfQoKcGFsIDwtIGNvbG9yTnVtZXJpYygidmlyaWRpcyIsIGRvbWFpbiA9IGRlbm9tYnJlbWVudENhcnRlJE1PUzExKQoKCmxlYWZsZXQoZGF0YSA9IGRlbm9tYnJlbWVudENhcnRlKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCLlBvc2l0cm9uIikgJT4lCiAgYWRkQ2lyY2xlcyhyYWRpdXMgPSAzMDAsIGNvbG9yID0gfnBhbChNT1MxMSksIGZpbGxPcGFjaXR5ID0gMC4yLCBwb3B1cCA9IH5wb3B1cF90ZXh0KSAlPiUKICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gcGFsLCB2YWx1ZXMgPSB+TU9TMTEsIHRpdGxlID0gIk1PUzExIiwgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKSAlPiUKICBhZGRTY2FsZUJhcihwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikKYGBgCkdyw6JjZSDDoCBjZXR0ZSBjYXJ0ZSwgbm91cyBvYnRlbm9ucyBsZSBjbGFzc2VtZW50IChUb3AgMykgZGVzIG9pc2VhdXggbGVzIHBsdXMgb2JzZXJ2w6lzIGRhbnMgY2hhcXVlIG1haWxsZSBkZSBtZXN1cmUgcG91ciBsJ2FubsOpZSAyMDIzLgpOb3VzIGF2b25zIMOpZ2FsZW1lbnQgYWpvdXTDqSB1bmUgaW5mb3JtYXRpb24gc3VwcGzDqW1lbnRhaXJlIHN1ciBjaGFxdWUgb2lzZWF1IHBvdXIgbWV0dHJlIGVuIMOpdmlkZW5jZSBzb24gbml2ZWF1IGRlIHNww6ljaWFsaXNhdGlvbiBhZmluIGRlIG1pZXV4IGNvbXByZW5kcmUgZGUgcXVlbCB0eXBlIGRlIG1pbGlldSBpbCBhIGJlc29pbiBwb3VyIHZpdnJlIGV0IGxhIGfDqW9sb2NhbGlzYXRpb24gc3VyIGxhIEdpcm9uZGUuCgpOb3VzIHBvdXZvbnMgdm9pciBxdWUgbGUgbml2ZWF1IGRlIHNww6ljaWFsaXNhdGlvbiBsZSBwbHVzIHLDqXBlbmR1IGVzdCBnw6luw6lyYWxpc3RlIGNhciBvbiBlbiByZXRyb3V2ZSBhdSBjZW50cmUtdmlsbGUgZXQgZW4gcMOpcmlwaMOpcmllLgpFZ2FsZW1lbnQsIGF1IGNlbnRyZSB2aWxsZSwgb24gcmV0cm91dmUgZGVzIG9pc2VhdXggZGUgdHlwZSBCw6J0aSBldCBlbiBww6lyaXBow6lyaWUgbG9pbnMgZHUgY2VudHJlLXZpbGxlLCBvbiByZXRyb3V2ZSBkZXMgb2lzZWF1eCBkZSB0eXBlIEbDtHJldCBldCBBZ3JpY29sZS4gUHJvY2hlIGRlcyBwb2ludHMgZCdlYXUsIG9uIHRyb3V2ZSBkZXMgb2lzZWF1eCBkZSB0eXBlIFpvbmUgaHVtaWRlLiAKCkFpbnNpLCBsZXMgem9uZXMgcXVpIGNvbWJpbmVudCDDoCBsYSBmb2lzIHbDqWfDqXRhdGlvbiBldCBiw6J0aW1lbnRzIHNlcmFpZW50IHBsdXMgc3VzY2VwdGlibGVzIGQnYWNjdWVpbGxpciBkZXMgb2lzZWF1eCBhdmVjIGRlcyBuaXZlYXV4IGRlIHNww6ljaWFsaXNhdGlvbiB2YXJpw6lzLCBjZSBxdWkgZXhwbGlxdWVyYWl0IGwnYXVnbWVudGF0aW9uIGR1IHRhdXggZGUgZGl2ZXJzaXTDqSBvYnNlcnbDqWUgZGFucyBsZXMgem9uZXMgb8O5IHNlIG3DqWxhbmdlbnQgZXNwYWNlcyB2ZXJ0cyBldCB6b25lcyB1cmJhbmlzw6llcy4KCklsIG5vdXMgc2VtYmxhaXQgaW50w6lyZXNzYW50IGRlIHNhdm9pciBxdWVscyDDqXRhaWVudCBsZXMgcsOpZ2ltZXMgYWxpbWVudGFpcmVzIG1ham9yaXRhaXJlcyBwcmluY2lwYXV4IGVuIGZvbmN0aW9uIGRlIGNoYXF1ZSBtYWlsbGUuCk5vdXMgYXZvbnMgZG9uYyBjcsOpw6kgdW4gZ3JhcGhpcXVlIHF1aSBtb250cmUgbGEgcsOpcGFydGl0aW9uIGRlcyByw6lnaW1lcyBhbGltZW50YWlyZXMgcG91ciBjaGFxdWUgbWFpbGxlLgoKYGBge3J9CiMgY2hhbmdlZCB0aGUgdW5tYXRjaGlubmcgbGF0aW4gbmFtZXMgdG8gdGhlIGNvcnJlY3Qgb25lcyB0byBtYXRjaCBhbGltZW50YXRpb24KZGVub21icmVtZW50JGxhdGluW2Rlbm9tYnJlbWVudCRsYXRpbiA9PSAiQ2FyZHVlbGlzIGNobG9yaXMiXSA8LSAiQ2hsb3JpcyBjaGxvcmlzIgpkZW5vbWJyZW1lbnQkbGF0aW5bZGVub21icmVtZW50JGxhdGluID09ICJDYXJkdWVsaXMgc3BpbnVzIl0gPC0gIlNwaW51cyBzcGludXMiCmRlbm9tYnJlbWVudCRsYXRpbltkZW5vbWJyZW1lbnQkbGF0aW4gPT0gIkNhc21lcm9kaXVzIGFsYnVzIl0gPC0gIkFyZGVhIGFsYmEiCmRlbm9tYnJlbWVudCRsYXRpbltkZW5vbWJyZW1lbnQkbGF0aW4gPT0gIkNhcmR1ZWxpcyBjYW5uYWJpbmEiXSA8LSAiTGluYXJpYSBjYW5uYWJpbmEiCm5vX2luZm8gPC0gYygiSGltYW50b3B1cyBoaW1hbnRvcHVzIiwgIlRyaW5nYSBvY2hyb3B1cyIsIAogICAgICAgICAgICAgIkNhcHJpbXVsZ3VzIGV1cm9wYWV1cyIsICJMYW5pdXMgc2VuYXRvciIsIAogICAgICAgICAgICAgIkRyeW9jb3B1cyBtYXJ0aXVzIiwgIkVtYmVyaXphIGNhbGFuZHJhIikKCmFsaW1lbnRhdGlvbiA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy90cmFpdHMtc3RhdHV0LUlVQ04tYmlvZGl2ZXJjaXRlLmNzdiIsIGhlYWRlciA9IFRSVUUpCmRlbm9tYnJlbWVudCRyZWdpbWVfYWxpbWVudGFpcmUgPC0gcmVwKE5BLCBucm93KGRlbm9tYnJlbWVudCkpCmZvciAoaSBpbiAxOm5yb3coZGVub21icmVtZW50KSkgewogIGlmIChkZW5vbWJyZW1lbnQkbGF0aW5baV0gJWluJSBub19pbmZvKXsKICAgIGRlbm9tYnJlbWVudCRyZWdpbWVfYWxpbWVudGFpcmVbaV0gPC0gTkEKICB9CiAgZWxzZSB7CiAgICBkZW5vbWJyZW1lbnQkcmVnaW1lX2FsaW1lbnRhaXJlW2ldIDwtIAogICAgICBhbGltZW50YXRpb24kUsOpZ2ltZS5hbGltZW50YWlyZVt3aGljaChhbGltZW50YXRpb24kTm9tLmxhdGluID09IGRlbm9tYnJlbWVudCRsYXRpbltpXSldCiAgfQp9CmRlbm9tYnJlbWVudCRyZWdpbWVfYWxpbWVudGFpcmUgPC0gYXMuZmFjdG9yKGRlbm9tYnJlbWVudCRyZWdpbWVfYWxpbWVudGFpcmUpCgpwbG90X2RhdGEgPSBmdW5jdGlvbiAoZGF0YSwgdGl0bGUpIHsKICAgIGdncGxvdChkYXRhLCBhZXMoeD0iIiwgeT1zdW0sIGZpbGw9cmVnaW1lX2FsaW1lbnRhaXJlKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjEpICsKICAgIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogICAgZ2d0aXRsZShwYXN0ZSgiU3RhdGlvbjogIiwgYXMuY2hhcmFjdGVyKHRpdGxlKSkpICsKICAgIHRoZW1lX3ZvaWQoKQp9CgpjaXRlIDwtIGNpdGUgJT4lCiAgc2VsZWN0KGNvZGVfc2l0ZSwgTm9tX2xpZXUpCgojT24gam9pbiBsZXMgZGV1eCB0YWJsZXMgY2l0ZSBldCBkZW5vbWJyZW1lbnRDYXJ0ZQoKZGVub21icmVtZW50IDwtIGxlZnRfam9pbihkZW5vbWJyZW1lbnQsIGNpdGUsIGJ5ID0gYygiQ29kZV9NYWlsbGUiID0gImNvZGVfc2l0ZSIpKQoKTiA8LSBsZW5ndGgodW5pcXVlKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSkpCnAgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoID0gTikKCmZvciAoaSBpbiAxOk4pIHsKICAgIGRhdGEgPC0gZGVub21icmVtZW50W3doaWNoKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSA9PSB1bmlxdWUoZGVub21icmVtZW50JENvZGVfTWFpbGxlKVtpXSksXQogICAgZGF0YSA8LSBkYXRhICU+JSBncm91cF9ieShyZWdpbWVfYWxpbWVudGFpcmUpICU+JSBzdW1tYXJpc2Uoc3VtID0gc3VtKHAsIG5hLnJtID0gVFJVRSkpCiAgICBwW1tpXV0gPC0gcGxvdF9kYXRhKGRhdGEsIHVuaXF1ZShkZW5vbWJyZW1lbnQkTm9tX2xpZXUpW2ldKQp9Cgpjb29yZGluYXRlcyA8LSBzdF9hc19zZihMVVAsIGNvb3JkcyA9IGMoIlgiLCAiWSIpLCBjcnMgPSAyMTU0KQpjb29yZGluYXRlcyA8LSBzdF90cmFuc2Zvcm0oY29vcmRpbmF0ZXMsIGNycyA9IDQzMjYpCmNvb3JkaW5hdGVzIDwtIGNvb3JkaW5hdGVzW2Nvb3JkaW5hdGVzJEJ1ZmZlclNpemUgPT0gNTAwLF0KCiMgUmVtb3ZlIHRoZSBjb29yZGluYXRlcyB0aGF0IGFyZSBub3QgaW4gZGVub21icmVtZW50CmZvciAoaSBpbiBzZXFfYWxvbmcoY29vcmRpbmF0ZXMkSUQpKXsKICBpZiAoIShjb29yZGluYXRlcyRJRFtpXSAlaW4lIHVuaXF1ZShkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGUpKSl7CiAgICBjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1staSxdCiAgfQp9Cgpjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1tvcmRlcihjb29yZGluYXRlcyRJRCwgZGVjcmVhc2luZyA9IFRSVUUpLF0KCnBhbCA8LSBjb2xvck51bWVyaWMoInZpcmlkaXMiLCBkb21haW4gPSBjb29yZGluYXRlcyRNT1MxMSkKbGVhZmxldChkYXRhID0gY29vcmRpbmF0ZXMpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICBhZGRDaXJjbGVzKHJhZGl1cyA9IDMwMCwgY29sb3IgPSB+cGFsKE1PUzExKSwgCiAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNSwgZ3JvdXAgPSAicG50IikgJT4lCiAgYWRkTGVnZW5kKCJib3R0b21yaWdodCIsIHBhbCA9IHBhbCwgdmFsdWVzID0gY29vcmRpbmF0ZXMkTU9TMTEsIHRpdGxlID0gIk1PUzExIikgJT4lCiAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tbGVmdCIpICU+JSAKICBhZGRQb3B1cEdyYXBocyhwLCB3aWR0aCA9IDIwMCwgaGVpZ2h0ID0gMjAwLCBncm91cCA9ICJwbnQiKQpgYGAKClZvaWNpIMOgIHF1b2kgcmVzc2VtYmxlIGxhIGNhcnRlIGludGVyYWN0aXZlIHF1aSBtb250cmUgbGVzIHLDqWdpbWVzIGFsaW1lbnRhaXJlcyBtYWpvcml0YWlyZXMgcHJpbmNpcGF1eCBlbiBmb25jdGlvbiBkZSBjaGFxdWUgbWFpbGxlLiBOb3VzIHBvdXZvbnMgdm9pciBxdSdlbiBnw6luw6lyYWwsIGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgZG9taW5hbnQgZXN0IGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgbWl4dGUsIHF1ZSBjZWxhIHNvaXQgYXUgY2VudHJlIGRlIEJvcmRlYXV4IG91IGVuIHDDqXJpcGjDqXJpZS4gSWwgc2VtYmxlIGRvbmMgcXVlIGxlIHLDqWdpbWUgYWxpbWVudGFpcmUgZGUgbCdvaXNlYXUgbmUgc29pdCBwYXMgdsOpcml0YWJsZW1lbnQgaW1wYWN0w6kgcGFyIGwnYXJ0aWZpY2lhbGlzYXRpb24gZGVzIHNvbHMuCkVzc2F5b25zIG1haW50ZW5hbnQgZCfDqXR1ZGllciBkJ2F1dHJlIGNhcmF0w6lyaXN0aXF1ZXMgYWZpbiBkJ2Vzc2F5ZXIgZGUgdHJvdXZlciBkZXMgcmFpc29ucyDDoCBjZSBwaWMgZGUgZGl2ZXJzaXTDqS4KCmBgYHtyfQpkZW5vbWJyZW1lbnQkTmlkaWZpY2F0aW9uIDwtIHJlcChOQSwgbnJvdyhkZW5vbWJyZW1lbnQpKQpmb3IgKGkgaW4gMTpucm93KGRlbm9tYnJlbWVudCkpIHsKICBpZiAoZGVub21icmVtZW50JGxhdGluW2ldICVpbiUgbm9faW5mbyl7CiAgICBkZW5vbWJyZW1lbnQkTmlkaWZpY2F0aW9uW2ldIDwtIE5BCiAgfQogIGVsc2UgewogICAgZGVub21icmVtZW50JE5pZGlmaWNhdGlvbltpXSA8LSAKICAgICAgYWxpbWVudGF0aW9uJE5pZGlmaWNhdGlvblt3aGljaChhbGltZW50YXRpb24kTm9tLmxhdGluID09IGRlbm9tYnJlbWVudCRsYXRpbltpXSldCiAgfQp9CmRlbm9tYnJlbWVudCROaWRpZmljYXRpb24gPC0gYXMuZmFjdG9yKGRlbm9tYnJlbWVudCROaWRpZmljYXRpb24pCgpwbG90X2RhdGEgPSBmdW5jdGlvbiAoZGF0YSwgdGl0bGUpIHsKICAgIGdncGxvdChkYXRhLCBhZXMoeD0iIiwgeT1zdW0sIGZpbGw9TmlkaWZpY2F0aW9uKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjEpICsKICAgIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogICAgZ2d0aXRsZShwYXN0ZSgiU3RhdGlvbjogIiwgYXMuY2hhcmFjdGVyKHRpdGxlKSkpICsKICAgIHRoZW1lX3ZvaWQoKQp9CgojT24gam9pbiBsZXMgZGV1eCB0YWJsZXMgY2l0ZSBldCBkZW5vbWJyZW1lbnRDYXJ0ZQoKTiA8LSBsZW5ndGgodW5pcXVlKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSkpCnAgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoID0gTikKCmZvciAoaSBpbiAxOk4pIHsKICAgIGRhdGEgPC0gZGVub21icmVtZW50W3doaWNoKGRlbm9tYnJlbWVudCRDb2RlX01haWxsZSA9PSB1bmlxdWUoZGVub21icmVtZW50JENvZGVfTWFpbGxlKVtpXSksXQogICAgZGF0YSA8LSBkYXRhICU+JSBncm91cF9ieShOaWRpZmljYXRpb24pICU+JSBzdW1tYXJpc2Uoc3VtID0gc3VtKHAsIG5hLnJtID0gVFJVRSkpCiAgICBwW1tpXV0gPC0gcGxvdF9kYXRhKGRhdGEsIHVuaXF1ZShkZW5vbWJyZW1lbnQkTm9tX2xpZXUpW2ldKQp9Cgpjb29yZGluYXRlcyA8LSBzdF9hc19zZihMVVAsIGNvb3JkcyA9IGMoIlgiLCAiWSIpLCBjcnMgPSAyMTU0KQpjb29yZGluYXRlcyA8LSBzdF90cmFuc2Zvcm0oY29vcmRpbmF0ZXMsIGNycyA9IDQzMjYpCmNvb3JkaW5hdGVzIDwtIGNvb3JkaW5hdGVzW2Nvb3JkaW5hdGVzJEJ1ZmZlclNpemUgPT0gNTAwLF0KCiMgUmVtb3ZlIHRoZSBjb29yZGluYXRlcyB0aGF0IGFyZSBub3QgaW4gZGVub21icmVtZW50CmZvciAoaSBpbiBzZXFfYWxvbmcoY29vcmRpbmF0ZXMkSUQpKXsKICBpZiAoIShjb29yZGluYXRlcyRJRFtpXSAlaW4lIHVuaXF1ZShkZW5vbWJyZW1lbnQkQ29kZV9NYWlsbGUpKSl7CiAgICBjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1staSxdCiAgfQp9Cgpjb29yZGluYXRlcyA8LSBjb29yZGluYXRlc1tvcmRlcihjb29yZGluYXRlcyRJRCwgZGVjcmVhc2luZyA9IFRSVUUpLF0KCnBhbCA8LSBjb2xvck51bWVyaWMoInZpcmlkaXMiLCBkb21haW4gPSBjb29yZGluYXRlcyRNT1MxMSkKbGVhZmxldChkYXRhID0gY29vcmRpbmF0ZXMpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICBhZGRDaXJjbGVzKHJhZGl1cyA9IDMwMCwgY29sb3IgPSB+cGFsKE1PUzExKSwgCiAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNSwgZ3JvdXAgPSAicG50MiIpICU+JQogIGFkZExlZ2VuZCgiYm90dG9tcmlnaHQiLCBwYWwgPSBwYWwsIHZhbHVlcyA9IGNvb3JkaW5hdGVzJE1PUzExLCB0aXRsZSA9ICJNT1MxMSIpICU+JQogIGFkZFNjYWxlQmFyKHBvc2l0aW9uID0gImJvdHRvbWxlZnQiKSAlPiUgCiAgYWRkUG9wdXBHcmFwaHMocCwgd2lkdGggPSAyMDAsIGhlaWdodCA9IDIwMCwgZ3JvdXAgPSAicG50MiIpCmBgYAoKCkNldHRlIGNhcnRlIGlsbHVzdHJlIGxhIHLDqXBhcnRpdGlvbiBkZXMgdHlwZXMgZGUgbmlkaWZpY2F0aW9uIGVuIGZvbmN0aW9uIGRlcyB6b25lcyBnw6lvZ3JhcGhpcXVlcy4gSWwgZXN0IG9ic2VydsOpIHF1ZSBkYW5zIGxlcyB6b25lcyBjZW50cmFsZXMsIGxhIG1ham9yaXTDqSBkZXMgbmlkcyBzb250IHNpdHXDqXMgZGFucyBkZXMgY2F2aXTDqXMsIGNlIHF1aSBwZXV0IMOqdHJlIGF0dHJpYnXDqSDDoCBsYSBkZW5zaXTDqSDDqWxldsOpZSBkZSBiw6J0aW1lbnRzIGV0IMOgIGxhIHJhcmV0w6kgZGUgbGEgdsOpZ8OpdGF0aW9uIGVuIHZpbGxlLiBMZSBtb2RlIGRlIG5pZGlmaWNhdGlvbiBhdSBzb2wgZXN0IGxlIG1vaW5zIGNvdXJhbnQgZGFucyBjZXMgem9uZXMsIHByb2JhYmxlbWVudCBlbiByYWlzb24gZGUgbGEgZmFpYmxlIHByb2JhYmlsaXTDqSBkZSBzdXJ2aWUgZGVzIG9pc2VhdXggZGFucyB1biBlbnZpcm9ubmVtZW50IHVyYmFpbiBhdmVjIHVuIG5pZCBhdSBzb2wuICAKCkVuIHDDqXJpcGjDqXJpZSwgbGVzIG1vZGVzIGRlIG5pZGlmaWNhdGlvbiBzZW1ibGVudCBwbHVzIGRpdmVyc2lmacOpcywgYXZlYyB1bmUgcHLDqWRvbWluYW5jZSBkZSBsYSBuaWRpZmljYXRpb24gZW4gYnVpc3Nvbi4gTGEgbmlkaWZpY2F0aW9uIGRhbnMgbGVzIGFyYnJlcyBlc3Qgw6lnYWxlbWVudCB0csOocyByw6lwYW5kdWUsIGV0IG9uIHJldHJvdXZlIGF1c3NpIGxhIG5pZGlmaWNhdGlvbiBlbiBjYXZpdMOpLiBMZSBmYWl0IGRlIG5lIHBhcyDDqnRyZSBzaXR1w6kgZGlyZWN0ZW1lbnQgYXUgY2VudHJlLXZpbGxlIHNlbWJsZSBvZmZyaXIgcGx1cyBkZSBwb3NzaWJpbGl0w6lzIGRlIG5pZGlmaWNhdGlvbiwgY2UgcXVpIHBvdXJyYWl0IGV4cGxpcXVlciB1bmUgcGx1cyBncmFuZGUgZGl2ZXJzaXTDqSBkJ2VzcMOoY2VzIHNpIG9uIHMnw6lsb2lnbmUgbMOpZ8OocmVtZW50IGR1IGNlbnRyZSB2aWxsZSwgZ3LDomNlIMOgIHVuZSBjb21iaW5haXNvbiBkZSBiw6J0aW1lbnRzIGV0IGRlIHbDqWfDqXRhdGlvbiBvZmZyYW50IHBsdXMgZGUgY2hvaXggcG91ciBsYSBuaWRpZmljYXRpb24uCgoKCgojIEFuYWx5c2UgZW4gQ29tcG9zYW50ZSBQcmluY2lwYWxlIChBQ1ApCgpgYGB7cn0KcGNhX3Jlc3VsdCA8LSBQQ0EoTFVQWywgNjoxOV0sIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQpmdml6X2VpZygKICBwY2FfcmVzdWx0LAogIGFkZGxhYmVscyA9IFRSVUUsCiAgbmNwID0gMTQKKQpgYGAKCmBgYHtyfQpmdml6X3BjYV92YXIoCiAgcGNhX3Jlc3VsdCwKICBjb2wudmFyID0gImNvbnRyaWIiLAogIGdyYWRpZW50LmNvbHMgPSByYWluYm93KDUpLAogIGxlZ2VuZC50aXRsZSA9ICJDb250cmlidXRpb24gKCUpIiwKICByZXBlbCA9IFRSVUUKKQpgYGAKCmBgYHtyfQpmdml6X3BjYV9pbmQoCiAgcGNhX3Jlc3VsdCwKICByZXBlbCA9IEZBTFNFCikKZnZpel9wY2FfYmlwbG90KAogIHBjYV9yZXN1bHQsCiAgcmVwZWwgPSBGQUxTRSwKICBjb2wudmFyID0gIiNFNTAwMDAiCikKYGBgCgpgYGB7cn0KYmlyZHNfaW5mbyA8LSByZWFkLmNzdigiZGF0YS9iaXJkcy90cmFpdHMtc3RhdHV0LUlVQ04tYmlvZGl2ZXJjaXRlLmNzdiIsIGhlYWRlciA9IFRSVUUpCmJpcmRzX2luZm8gPC0gYmlyZHNfaW5mb1ssIGMoCiAgIk5vbS5sYXRpbiIsCiAgIk5pdmVhdS5kZS5zcMOpY2lhbGlzYXRpb24iLAogICJSw6lnaW1lLmFsaW1lbnRhaXJlIiwKICAiVGVjaG5pcXVlLmQuYWxpbWVudGF0aW9uIiwKICAiTmlkaWZpY2F0aW9uIiwKICAiUMOpcmlvZGUuZGUubWlncmF0aW9uIgopXQoKZGVub21icmVtZW50CkxVUApgYGAKCgojIFBvdXIgYWxsZXIgcGx1cyBsb2luCgpDZXR0ZSBzZWN0aW9uIGVzdCBkw6lkacOpZSDDoCBkZXMgYW5hbHlzZXMgcGx1cyBwb3Vzc8OpZXMgcXVpIHBvdXJyYWllbnQgw6p0cmUgcsOpYWxpc8OpZXMgcG91ciBtaWV1eCBjb21wcmVuZHJlIGxlcyBkb25uw6llcyBldCBsZXMgcmVsYXRpb25zIGVudHJlIGxlcyBkaWZmw6lyZW50ZXMgdmFyaWFibGVzLgpWb3VzIHRyb3V2ZXJleiB1biBQYXJhbGxlbCBDb29yZGluYXRlcyBQbG90IGFpbnNpIHF1J3VuIHN1biBidXJzdCBwbG90IHF1aSBpbGx1c3RyZW50IGxlcyBjYXJhY3TDqXJpc3RpcXVlcyBkZXMgZGlmZsOpcmVudGVzIGVzcMOoY2VzIGQnb2lzZWF1eC4KCgpWb2ljaSwgY2ktZGVzc291cyBsZSBQYXJhbGxlbCBDb29yZGluYXRlcyBQbG90IGludMOpcmFjdGlmLgpWb3VzIHBvdXZleiBjbGlxdWVyIHN1ciBsZXMgZGlmZsOpcmVudGVzIGVzcMOoY2VzIHBvdXIgb2J0ZW5pciBwbHVzIGQnaW5mb3JtYXRpb25zIHN1ciBjaGFjdW5lIGQnZWxsZXMuCgpFeGVtcGxlIGQndXRpbGlzYXRpb24gOiAKCi0gTm91cyB2b3Vsb25zIHNhdm9pciBsZSByw6lnaW1lIGFsaW1lbnRhaXJlIGRlcyBvaXNlYXV4IHF1aSBtaWdyZW50LiAKUG91ciBjZWxhLCBpbCBzdWZmaXQgZGUgY2xpcXVlciBhdSBuaXZlYXUgZGUgIm1pZ3JhdGV1ciB0YXJkaWYiIGV0IGRlIGNsaXF1ZXIgc3VyICJWw6lnw6l0YXJpZW4iLCAiTWl4dGUiIG91ICJjYXJuaXZvcmUiIHBvdXIgb2J0ZW5pciBsZXMgZXNww6hjZXMgZCdvaXNlYXV4IHF1aSBjb3JyZXNwb25kZW50IMOgIGNlcyBjcml0w6hyZXMuCkNlY2kgZXN0IHRyw6hzIHV0aWxlIGxvcnNxdSdvbiB2ZXV0IGNvbXBhcmVyIGxlIG5vbWJyZSBkJ29pc2VhdSBzZWxvbiBsZXMgY2FyYWN0w6lyaXN0aXF1ZXMgY2hvaXNpZXMgb3UgbcOqbWUgc2ltcGxlbWVudCByZWNoZXJjaGVyIGwnZXNww6hjZSBxdWkgY29ycmVzcG9uZCDDoCBjZXJ0YWlucyBjcml0w6hyZXMgcXVlIGwnb24gdmV1dCDDqXR1ZGllci4KUG91ciBmaW5pciBsJ2V4ZW1wbGUsIHNpIG9uIGNsaXF1ZSBhdSBuaXZlYXUgZGUgIk1pZ3JhdGV1ciB0YXJkaWYiLCBvbiByZW1hcnF1ZSBxdSdhdWN1biBvaXNlYXUgbidlc3QgdsOpZ8OpdGFyaWVuLgpEZSBwbHVzLCBvbiBwZXV0IGFmZmluZXIgbm90cmUgc8OpbGVjdGlvbiBwb3VyIHZvaXIgcXVlbGxlcyBlc3DDqGNlcyBkJ29pc2VhdXggc29udCBkZXMgbWlncmF0ZXVycyB0YXJkaWZzIGV0IGZvbnQgbGV1ciBuaWQgZGFucyBsZXMgYnVpc3NvbnMuCk9uIGNsaXF1ZSBhaW5zaSBzdXIgYnVpc3NvbiBldCBvbiB2b2l0IHF1ZSBsJ2VzcMOoY2UgIkxhbml1cyBjb2xsdXJpbyIgY29ycmVzcG9uZCDDoCBjZXMgY3JpdMOocmVzLgpDJ2VzdCB1bmUgZXNww6hjZSBjYXJuaXZvcmUgcXVpIG1pZ3JlIHRhcmRpdmVtZW50IGV0IGZhaXQgc29uIG5pZCBkYW5zIGxlcyBidWlzc29ucyBxdWkgYSB1biBuaXZlYXUgZGUgc3DDqWNpYWxpc2F0aW9uIGFncmljb2xlIGV0IHF1aSBzJ2FsaW1lbnRlIGVuIHZvbC4KCgo8Y2VudGVyPgogICFbVm9pY2kgdW5lIGltYWdlIGRlIGxhIHBpZS1ncmnDqGNoZSDDqWNvcmNoZXVyIChMYW5pdXMgY29sbHVyaW8pLCB3aWtpcGVkaWFdKC4vaW1hZ2UvbGFuaXVzLmpwZykKPC9jZW50ZXI+CgpgYGB7cn0KdW5pcXVlX2xldmVsIDwtIHVuaXF1ZShiaXJkc19pbmZvWywgIk5pdmVhdS5kZS5zcMOpY2lhbGlzYXRpb24iXSkKdW5pcXVlX3JlZ2ltZSA8LSB1bmlxdWUoYmlyZHNfaW5mb1ssICJSw6lnaW1lLmFsaW1lbnRhaXJlIl0pCnVuaXF1ZV90ZWNobmlxdWUgPC0gdW5pcXVlKGJpcmRzX2luZm9bLCAiVGVjaG5pcXVlLmQuYWxpbWVudGF0aW9uIl0pCnVuaXF1ZV9uaWRpIDwtIHVuaXF1ZShiaXJkc19pbmZvWywgIk5pZGlmaWNhdGlvbiJdKQp1bmlxdWVfbWlncmF0aW9uIDwtIHVuaXF1ZShiaXJkc19pbmZvWywgIlDDqXJpb2RlLmRlLm1pZ3JhdGlvbiJdKQoKcGxvdF9seShkYXRhLmZyYW1lKCksIHR5cGUgPSAicGFyY29vcmRzIiwgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIpLCBoZWlnaHQgPSA5NTAsCiAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICBsaXN0KAogICAgICBsYWJlbCA9ICJFc3DDqGNlcyIsCiAgICAgIHJhbmdlID0gYygwLCBsZW5ndGgoYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSkgKyAxKSwKICAgICAgdGlja3ZhbHMgPSAxOmxlbmd0aChiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdKSwKICAgICAgdGlja3RleHQgPSBiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdLAogICAgICB2YWx1ZXMgPSAxOmxlbmd0aChiaXJkc19pbmZvWywgIk5vbS5sYXRpbiJdKQogICAgKSwKICAgIGxpc3QoCiAgICAgIGxhYmVsID0gIlRlY2huaXF1ZSBkJ2FsaW1lbnRhdGlvbiIsCiAgICAgIHJhbmdlID0gYygwLCBsZW5ndGgodW5pcXVlX3RlY2huaXF1ZSkgKyAxKSwKICAgICAgdGlja3ZhbHMgPSBhcy5udW1lcmljKGZhY3Rvcih1bmlxdWVfdGVjaG5pcXVlKSksCiAgICAgIHRpY2t0ZXh0ID0gdW5pcXVlX3RlY2huaXF1ZSwKICAgICAgdmFsdWVzID0gYXMubnVtZXJpYyhmYWN0b3IoYmlyZHNfaW5mb1ssICJUZWNobmlxdWUuZC5hbGltZW50YXRpb24iXSkpCiAgICApLAogICAgbGlzdCgKICAgICAgbGFiZWwgPSAiTmlkaWZpY2F0aW9uIiwKICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aCh1bmlxdWVfbmlkaSkgKyAxKSwKICAgICAgdGlja3ZhbHMgPSBhcy5udW1lcmljKGZhY3Rvcih1bmlxdWVfbmlkaSkpLAogICAgICB0aWNrdGV4dCA9IHVuaXF1ZV9uaWRpLAogICAgICB2YWx1ZXMgPSBhcy5udW1lcmljKGZhY3RvcihiaXJkc19pbmZvWywgIk5pZGlmaWNhdGlvbiJdKSkKICAgICksCiAgICBsaXN0KAogICAgICBsYWJlbCA9ICJOaXZlYXUgZGUgc3DDqWNpYWxpc2F0aW9uIiwKICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aCh1bmlxdWVfbGV2ZWwpICsgMSksCiAgICAgIHRpY2t2YWxzID0gYXMubnVtZXJpYyhmYWN0b3IodW5pcXVlX2xldmVsKSksCiAgICAgIHRpY2t0ZXh0ID0gdW5pcXVlX2xldmVsLAogICAgICB2YWx1ZXMgPSBhcy5udW1lcmljKGZhY3RvcihiaXJkc19pbmZvWywgIk5pdmVhdS5kZS5zcMOpY2lhbGlzYXRpb24iXSkpCiAgICApLAogICAgbGlzdCgKICAgICAgbGFiZWwgPSAiUMOpcmlvZGUgZGUgbWlncmF0aW9uIiwKICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aCh1bmlxdWVfbWlncmF0aW9uKSArIDEpLAogICAgICB0aWNrdmFscyA9IGFzLm51bWVyaWMoZmFjdG9yKHVuaXF1ZV9taWdyYXRpb24pKSwKICAgICAgdGlja3RleHQgPSB1bmlxdWVfbWlncmF0aW9uLAogICAgICB2YWx1ZXMgPSBhcy5udW1lcmljKGZhY3RvcihiaXJkc19pbmZvWywgIlDDqXJpb2RlLmRlLm1pZ3JhdGlvbiJdKSkKICAgICksCiAgICBsaXN0KAogICAgICBsYWJlbCA9ICJSw6lnaW1lIGFsaW1lbnRhaXJlIiwKICAgICAgcmFuZ2UgPSBjKDAsIGxlbmd0aCh1bmlxdWVfcmVnaW1lKSArIDEpLAogICAgICB0aWNrdmFscyA9IGFzLm51bWVyaWMoZmFjdG9yKHVuaXF1ZV9yZWdpbWUpKSwKICAgICAgdGlja3RleHQgPSB1bmlxdWVfcmVnaW1lLAogICAgICB2YWx1ZXMgPSBhcy5udW1lcmljKGZhY3RvcihiaXJkc19pbmZvWywgIlLDqWdpbWUuYWxpbWVudGFpcmUiXSkpCiAgICApCiAgKQopICU+JSBsYXlvdXQoCiAgdGl0bGUgPSAiQ2FyYWN0w6lyaXN0aXF1ZXMgZGVzIGRpZmbDqXJlbnRlcyBlc3DDqGNlcyBkJ29pc2VhdXgiLAogIG1hcmdpbiA9IGxpc3QobCA9IDE0MCwgciA9IDU1KQopCmBgYAoKCmBgYHtyfQpMVVAgPC0gcmVhZC5jc3YoImRhdGEvYmlyZHMvTGFuZFVzZVBlcl9CTV8yMDIzX2NhcnRvSVNlYS5jc3YiLCBoZWFkZXIgPSBUUlVFKQpMVVAgPC0gTFVQWywgYyhjKCJJRCIsICJCdWZmZXJTaXplIiksIHBhc3RlMCgiTU9TIiwgMToxNCkpXQoKYmlyZHNfb2JzIDwtIHJlYWQuY3N2KCJkYXRhL2JpcmRzL09pc2VhdXhfdXBfdG9fMjAyMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQpiaXJkc19vYnMgPC0gYmlyZHNfb2JzWywgYyhjKCJDb2RlX01haWxsZSIsICJEYXRlIiwgIk5vbV9UYXhvbl9DaXRlIiwgIkRlbm9tYnJlbWVudF9taW4iKSldCmJpcmRzX29icyA8LSBiaXJkc19vYnMgJT4lCiAgcmVuYW1lKFllYXIgPSBEYXRlLCBJRCA9IENvZGVfTWFpbGxlLCBMYXRpbiA9IE5vbV9UYXhvbl9DaXRlKQoKYmlyZHNfb2JzWywgIlllYXIiXSA8LSBzdWJzdHIoYmlyZHNfb2JzWywgIlllYXIiXSwgc3RhcnQgPSAxLCBzdG9wID0gNCkKYmlyZHNfb2JzWywgIkxhdGluIl0gPC0gc2FwcGx5KHN0cnNwbGl0KGJpcmRzX29ic1ssICJMYXRpbiJdLCBzcGxpdCA9ICIgfCAiLCBmaXhlZCA9IFRSVUUpLCBmdW5jdGlvbih4KSB4WzFdKQoKYmlyZHNfb2JzIDwtIGJpcmRzX29icyAlPiUKICBncm91cF9ieShJRCwgWWVhciwgTGF0aW4pICU+JQogIHN1bW1hcmlzZShTdW0gPSBzdW0oRGVub21icmVtZW50X21pbiksIC5ncm91cHMgPSAiZHJvcCIpCgpMVVBfYmlyZHNfb2JzIDwtIG1lcmdlKExVUCwgYmlyZHNfb2JzLCBieSA9ICJJRCIpCmBgYAoKYGBge3J9CnVuaXF1ZV95ZWFyIDwtIHVuaXF1ZShMVVBfYmlyZHNfb2JzWywgIlllYXIiXSkKdW5pcXVlX3llYXIgPC0gdW5pcXVlX3llYXJbb3JkZXIodW5pcXVlX3llYXIpXQoKaWRzIDwtIGMoIkFubsOpZSIsIHVuaXF1ZV95ZWFyKQpmb3IgKHllYXIgaW4gdW5pcXVlX3llYXIpIHsKICBpZHMgPC0gYyhpZHMsIHBhc3RlMCh5ZWFyLCBwYXN0ZTAoIiAtIE1PUyIsIDE6MTQpKSkKfQoKZm9yICh5ZWFyIGluIHVuaXF1ZV95ZWFyKSB7CiAgZm9yIChtb3MgaW4gcGFzdGUwKCJNT1MiLCAxOjE0KSkgewogICAgZm9yIChzcGVjaWUgaW4gYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSkgewogICAgICBpZHMgPC0gYyhpZHMsIHBhc3RlMCh5ZWFyLCBwYXN0ZTAocGFzdGUwKCIgLSAiLCBtb3MpLCBwYXN0ZTAoIiAtICIsIHNwZWNpZSkpKSkKICAgIH0KICB9Cn0KCmxhYmVscyA8LSBjKCJBbm7DqWUiLCB1bmlxdWVfeWVhciwgcmVwKHBhc3RlMCgiTU9TIiwgMToxNCksIHRpbWVzID0gbGVuZ3RoKHVuaXF1ZV95ZWFyKSkpCmxhYmVscyA8LSBjKGxhYmVscywgcmVwKGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0sIHRpbWVzID0gMTQgKiBsZW5ndGgodW5pcXVlX3llYXIpKSkKCnBhcmVudHMgPC0gYygiIiwgcmVwKCJBbm7DqWUiLCB0aW1lcyA9IGxlbmd0aCh1bmlxdWVfeWVhcikpLCByZXAodW5pcXVlX3llYXIsIGVhY2ggPSAxNCkpCmZvciAoeWVhciBpbiB1bmlxdWVfeWVhcikgewogIHBhcmVudHMgPC0gYyhwYXJlbnRzLCBwYXN0ZTAoeWVhciwgcmVwKHBhc3RlMCgiIC0gTU9TIiwgMToxNCksIGVhY2ggPSBsZW5ndGgoYmlyZHNfaW5mb1ssICJOb20ubGF0aW4iXSkpKSkKfQoKdmFsdWVzIDwtIGMoYyhsZW5ndGgodW5pcXVlX3llYXIpICogMTQwMDAsIHJlcCgxNDAwMCwgdGltZXMgPSBsZW5ndGgodW5pcXVlX3llYXIpKSksIHJlcCgxMDAwLCB0aW1lcyA9IGxlbmd0aCh1bmlxdWVfeWVhcikgKiAxNCkpCmZvciAoeWVhciBpbiB1bmlxdWVfeWVhcikgewogIGZvciAobW9zIGluIHBhc3RlMCgiTU9TIiwgMToxNCkpIHsKICAgIGZvciAoc3BlY2llIGluIGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pIHsKICAgICAgdG1wIDwtIExVUF9iaXJkc19vYnNbTFVQX2JpcmRzX29ic1siWWVhciJdID09IHllYXIgJiBMVVBfYmlyZHNfb2JzWyJMYXRpbiJdID09IHNwZWNpZSAmIExVUF9iaXJkc19vYnNbIkJ1ZmZlclNpemUiXSA9PSA1MDAsIF0KICAgICAgdmFsdWVzIDwtIGModmFsdWVzLCBzdW0odG1wW21vc10gKiB0bXBbIlN1bSJdKSkKICAgIH0KICAgIHRhaWxfdmFsdWVzIDwtIHZhbHVlc1soMSArIGxlbmd0aCh2YWx1ZXMpIC0gbGVuZ3RoKGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pKTpsZW5ndGgodmFsdWVzKV0KICAgIHZhbHVlc1soMSArIGxlbmd0aCh2YWx1ZXMpIC0gbGVuZ3RoKGJpcmRzX2luZm9bLCAiTm9tLmxhdGluIl0pKTpsZW5ndGgodmFsdWVzKV0gPC0gdGFpbF92YWx1ZXMgLyBzdW0odGFpbF92YWx1ZXMpICogMTAwMAogIH0KfQoKaXNfbmFuX3ZhbHVlcyA8LSAhaXMubmEodmFsdWVzKSAmIHZhbHVlcyAhPSAwCmlkcyA8LSBpZHNbaXNfbmFuX3ZhbHVlc10KbGFiZWxzIDwtIGxhYmVsc1tpc19uYW5fdmFsdWVzXQpwYXJlbnRzIDwtIHBhcmVudHNbaXNfbmFuX3ZhbHVlc10KdmFsdWVzIDwtIHZhbHVlc1tpc19uYW5fdmFsdWVzXQpgYGAKCgpDaS1kZXNzb3VzLCB2b3VzIHRyb3V2ZXJleiB1biBzdW5idXJzdCBwbG90IGludGVyYWN0aWYgcXVpIGlsbHVzdHJlIGxhIHByb3BvcnRpb24gZGVzIGVzcMOoY2VzIGQnb2lzZWF1eCBsZXMgcGx1cyBjb3VyYW1tZW50IG9ic2VydsOpZXMgZW4gZm9uY3Rpb24gZGUgbCdhbm7DqWUgZXQgZHUgTU9TLgpJbCBlc3QgYXNzZXogc2ltcGxlIGQndXRpbGlzYXRpb24sIGlsIHN1ZmZpdCBkZSBjbGlxdWVyIHN1ciBsZXMgZGlmZsOpcmVudGVzIHBhcnRpZXMgZHUgZ3JhcGhpcXVlIHBvdXIgb2J0ZW5pciBwbHVzIGQnaW5mb3JtYXRpb25zIHN1ciBsZXMgZXNww6hjZXMgZCdvaXNlYXV4IGxlcyBwbHVzIGNvdXJhbW1lbnQgb2JzZXJ2w6llcyBlbiBmb25jdGlvbiBkZSBsJ2FubsOpZSBldCBkdSBNT1MuCgpgYGB7cn0KcGxvdF9seSgKICBpZHMgPSBpZHMsCiAgbGFiZWxzID0gbGFiZWxzLAogIHBhcmVudHMgPSBwYXJlbnRzLAogIHZhbHVlcyA9IHZhbHVlcywKICB0eXBlID0gInN1bmJ1cnN0IiwKICBicmFuY2h2YWx1ZXMgPSAidG90YWwiLAogIG1heGRlcHRoID0gMiwKICBpbnNpZGV0ZXh0b3JpZW50YXRpb24gPSAicmFkaWFsIiwKICBob3ZlcmluZm8gPSAibGFiZWwrcGVyY2VudCBlbnRyeSIKKSAlPiUgbGF5b3V0KAogIHRpdGxlID0gbGlzdCgKICAgIHRleHQgPSAiUHJvcG9ydGlvbiBkZXMgZXNww6hjZXMgZCdvaXNlYXV4IGxlcyBwbHVzIGNvdXJhbW1lbnQgb2JzZXJ2w6llczxicj5lbiBmb25jdGlvbiBkZSBsJ2FubsOpZSBldCBkdSBNT1MiLAogICAgeSA9IDEuMQogICksCiAgbWFyZ2luID0gbGlzdCh0ID0gMTAwKQopCmBgYAoKIyBDb25jbHVzaW9u